mirror of https://github.com/odrling/Aegisub
Drop format and header lines from the in-memory file representation
They're just pointless cruft, so drop them from the file when parsing and re-add them when saving as ASS or SSA.
This commit is contained in:
parent
30ceced39f
commit
b94547aa71
|
@ -37,15 +37,7 @@
|
|||
#include "ass_entry.h"
|
||||
|
||||
wxString AssEntry::GetSSAText() const {
|
||||
wxString lower = data.Lower();
|
||||
|
||||
// Special cases
|
||||
if (lower == "[v4+ styles]") return "[V4 Styles]";
|
||||
if (lower == "scripttype: v4.00+") return "ScriptType: v4.00";
|
||||
if (lower.Left(7) == "format:") {
|
||||
if (group.Lower() == "[events]") return "Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text";
|
||||
if (group.Lower() == "[v4+ styles]") return "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding";
|
||||
}
|
||||
if (data.Lower() == "scripttype: v4.00+") return "ScriptType: v4.00";
|
||||
return GetEntryData();
|
||||
}
|
||||
|
||||
|
|
|
@ -98,9 +98,9 @@ void AssFile::Load(const wxString &_filename, wxString const& charset) {
|
|||
|
||||
// And if it doesn't add defaults for each
|
||||
if (!found_style)
|
||||
temp.InsertStyle(new AssStyle);
|
||||
temp.InsertLine(new AssStyle);
|
||||
if (!found_dialogue)
|
||||
temp.InsertDialogue(new AssDialogue);
|
||||
temp.InsertLine(new AssDialogue);
|
||||
|
||||
swap(temp);
|
||||
}
|
||||
|
@ -171,20 +171,29 @@ wxString AssFile::AutoSave() {
|
|||
return dstpath.GetFullPath();
|
||||
}
|
||||
|
||||
static void write_line(wxString const& line, std::vector<char>& dst) {
|
||||
wxCharBuffer buffer = (line + "\r\n").utf8_str();
|
||||
copy(buffer.data(), buffer.data() + buffer.length(), back_inserter(dst));
|
||||
}
|
||||
|
||||
void AssFile::SaveMemory(std::vector<char> &dst) {
|
||||
// Check if subs contain at least one style
|
||||
// Add a default style if they don't for compatibility with libass/asa
|
||||
if (GetStyles().Count() == 0)
|
||||
InsertStyle(new AssStyle);
|
||||
if (GetStyles().empty())
|
||||
InsertLine(new AssStyle);
|
||||
|
||||
// Prepare vector
|
||||
dst.clear();
|
||||
dst.reserve(0x4000);
|
||||
|
||||
// Write file
|
||||
wxString group;
|
||||
for (auto const& line : Line) {
|
||||
wxCharBuffer buffer = (line.GetEntryData() + "\r\n").utf8_str();
|
||||
copy(buffer.data(), buffer.data() + buffer.length(), back_inserter(dst));
|
||||
if (group != line.group) {
|
||||
group = line.group;
|
||||
write_line(group, dst);
|
||||
}
|
||||
write_line(line.GetEntryData(), dst);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -211,7 +220,6 @@ void AssFile::LoadDefault(bool defline) {
|
|||
Clear();
|
||||
|
||||
// Write headers
|
||||
Line.push_back(*new AssEntry("[Script Info]", "[Script Info]"));
|
||||
Line.push_back(*new AssEntry("Title: Default Aegisub file", "[Script Info]"));
|
||||
Line.push_back(*new AssEntry("ScriptType: v4.00+", "[Script Info]"));
|
||||
Line.push_back(*new AssEntry("WrapStyle: 0", "[Script Info]"));
|
||||
|
@ -223,10 +231,7 @@ void AssFile::LoadDefault(bool defline) {
|
|||
}
|
||||
Line.push_back(*new AssEntry("YCbCr Matrix: None", "[Script Info]"));
|
||||
|
||||
InsertStyle(new AssStyle);
|
||||
|
||||
Line.push_back(*new AssEntry("[Events]", "[Events]"));
|
||||
Line.push_back(*new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]"));
|
||||
Line.push_back(*new AssStyle);
|
||||
|
||||
if (defline)
|
||||
Line.push_back(*new AssDialogue);
|
||||
|
@ -260,37 +265,23 @@ AssFile& AssFile::operator=(AssFile from) {
|
|||
return *this;
|
||||
}
|
||||
|
||||
static bool try_insert(EntryList &lines, AssEntry *entry) {
|
||||
if (lines.empty()) return false;
|
||||
void AssFile::InsertLine( AssEntry *entry) {
|
||||
if (Line.empty()) {
|
||||
Line.push_back(*entry);
|
||||
return;
|
||||
}
|
||||
|
||||
// Search for insertion point
|
||||
entryIter it = lines.end();
|
||||
entryIter it = Line.end();
|
||||
do {
|
||||
--it;
|
||||
if (it->group == entry->group) {
|
||||
lines.insert(++it, *entry);
|
||||
return true;
|
||||
Line.insert(++it, *entry);
|
||||
return;
|
||||
}
|
||||
} while (it != lines.begin());
|
||||
} while (it != Line.begin());
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void AssFile::InsertStyle(AssStyle *style) {
|
||||
if (try_insert(Line, style)) return;
|
||||
|
||||
// No styles found, add them
|
||||
Line.push_back(*new AssEntry("[V4+ Styles]", "[V4+ Styles]"));
|
||||
Line.push_back(*new AssEntry("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", "[V4+ Styles]"));
|
||||
Line.push_back(*style);
|
||||
}
|
||||
|
||||
void AssFile::InsertAttachment(AssAttachment *attach) {
|
||||
if (try_insert(Line, attach)) return;
|
||||
|
||||
// Didn't find a group of the appropriate type so create it
|
||||
Line.push_back(*new AssEntry(attach->group, attach->group));
|
||||
Line.push_back(*attach);
|
||||
Line.push_back(*entry);
|
||||
}
|
||||
|
||||
void AssFile::InsertAttachment(wxString filename) {
|
||||
|
@ -303,16 +294,7 @@ void AssFile::InsertAttachment(wxString filename) {
|
|||
std::unique_ptr<AssAttachment> newAttach(new AssAttachment(wxFileName(filename).GetFullName(), group));
|
||||
newAttach->Import(filename);
|
||||
|
||||
InsertAttachment(newAttach.release());
|
||||
}
|
||||
|
||||
void AssFile::InsertDialogue(AssDialogue *diag) {
|
||||
if (try_insert(Line, diag)) return;
|
||||
|
||||
// Didn't find a group of the appropriate type so create it
|
||||
Line.push_back(*new AssEntry("[Events]", "[Events]"));
|
||||
Line.push_back(*new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]"));
|
||||
Line.push_back(*diag);
|
||||
InsertLine(newAttach.release());
|
||||
}
|
||||
|
||||
wxString AssFile::GetScriptInfo(wxString key) const {
|
||||
|
@ -373,7 +355,6 @@ void AssFile::SetScriptInfo(wxString const& key, wxString const& value) {
|
|||
// Script info section not found, so add it at the beginning of the file
|
||||
else {
|
||||
Line.push_front(*new AssEntry(key + ": " + value, "[Script Info]"));
|
||||
Line.push_front(*new AssEntry("[Script Info]", "[Script Info]"));
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -102,14 +102,10 @@ public:
|
|||
/// @brief Load default file
|
||||
/// @param defline Add a blank line to the file
|
||||
void LoadDefault(bool defline=true);
|
||||
/// Add a style to the file
|
||||
void InsertStyle(AssStyle *style);
|
||||
/// Add an attachment to the file
|
||||
void InsertAttachment(AssAttachment *attach);
|
||||
/// Add a line to the file at the end of the appropriate section
|
||||
void InsertLine(AssEntry *line);
|
||||
/// Attach a file to the ass file
|
||||
void InsertAttachment(wxString filename);
|
||||
/// Add a dialogue line to the file
|
||||
void InsertDialogue(AssDialogue *diag);
|
||||
/// Get the names of all of the styles available
|
||||
wxArrayString GetStyles() const;
|
||||
/// @brief Get a style by name
|
||||
|
|
|
@ -72,10 +72,6 @@ void AssParser::ParseScriptInfoLine(wxString const& data) {
|
|||
return;
|
||||
}
|
||||
|
||||
// If the first nonblank line isn't a header pretend it starts with [Script Info]
|
||||
if (target->Line.empty())
|
||||
target->Line.push_back(*new AssEntry("[Script Info]", "[Script Info]"));
|
||||
|
||||
if (data.StartsWith("ScriptType:")) {
|
||||
wxString versionString = data.Mid(11).Trim(true).Trim(false).Lower();
|
||||
int trueVersion;
|
||||
|
@ -97,15 +93,11 @@ void AssParser::ParseScriptInfoLine(wxString const& data) {
|
|||
void AssParser::ParseEventLine(wxString const& data) {
|
||||
if (data.StartsWith("Dialogue:") || data.StartsWith("Comment:"))
|
||||
target->Line.push_back(*new AssDialogue(data));
|
||||
else if (data.StartsWith("Format:"))
|
||||
target->Line.push_back(*new AssEntry("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text", "[Events]"));
|
||||
}
|
||||
|
||||
void AssParser::ParseStyleLine(wxString const& data) {
|
||||
if (data.StartsWith("Style:"))
|
||||
target->Line.push_back(*new AssStyle(data, version));
|
||||
else if (data.StartsWith("Format:"))
|
||||
target->Line.push_back(*new AssEntry("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding", "[V4+ Styles]"));
|
||||
}
|
||||
|
||||
void AssParser::ParseFontLine(wxString const& data) {
|
||||
|
@ -150,23 +142,16 @@ void AssParser::AddLine(wxString const& data) {
|
|||
version = 1;
|
||||
state = &AssParser::ParseStyleLine;
|
||||
}
|
||||
else if (low == "[events]") {
|
||||
else if (low == "[events]")
|
||||
state = &AssParser::ParseEventLine;
|
||||
}
|
||||
else if (low == "[script info]") {
|
||||
else if (low == "[script info]")
|
||||
state = &AssParser::ParseScriptInfoLine;
|
||||
}
|
||||
else if (low == "[graphics]") {
|
||||
else if (low == "[graphics]")
|
||||
state = &AssParser::ParseGraphicsLine;
|
||||
}
|
||||
else if (low == "[fonts]") {
|
||||
else if (low == "[fonts]")
|
||||
state = &AssParser::ParseFontLine;
|
||||
}
|
||||
else {
|
||||
else
|
||||
state = &AssParser::AppendUnknownLine;
|
||||
}
|
||||
|
||||
target->Line.push_back(*new AssEntry(header, header));
|
||||
return;
|
||||
}
|
||||
|
||||
|
|
|
@ -213,23 +213,11 @@ namespace Automation4 {
|
|||
if (StringEmptyOrWhitespace(raw)) {
|
||||
set_field(L, "class", "clear");
|
||||
}
|
||||
else if (raw[0] == ';') {
|
||||
// "text" field, same as "raw" but with semicolon stripped
|
||||
set_field(L, "text", raw.Mid(1));
|
||||
set_field(L, "class", "comment");
|
||||
}
|
||||
else if (raw[0] == '[') {
|
||||
set_field(L, "class", "head");
|
||||
}
|
||||
else if (e->group.Lower() == "[script info]") {
|
||||
set_field(L, "key", raw.BeforeFirst(':'));
|
||||
set_field(L, "value", raw.AfterFirst(':'));
|
||||
set_field(L, "class", "info");
|
||||
}
|
||||
else if (raw.Left(7).Lower() == "format:") {
|
||||
// TODO: parse the format line; just use a tokenizer
|
||||
set_field(L, "class", "format");
|
||||
}
|
||||
else if (AssDialogue *dia = dynamic_cast<AssDialogue*>(e)) {
|
||||
set_field(L, "comment", dia->Comment);
|
||||
|
||||
|
@ -317,20 +305,9 @@ namespace Automation4 {
|
|||
try {
|
||||
wxString section = get_wxstring_field(L, "section", "common");
|
||||
|
||||
if (lclass == "clear")
|
||||
result = new AssEntry("", "");
|
||||
else if (lclass == "comment")
|
||||
result = new AssEntry(";" + get_wxstring_field(L, "text", "comment"), section);
|
||||
else if (lclass == "head")
|
||||
result = new AssEntry(section, section);
|
||||
else if (lclass == "info") {
|
||||
if (lclass == "info") {
|
||||
result = new AssEntry(wxString::Format("%s: %s", get_wxstring_field(L, "key", "info"), get_wxstring_field(L, "value", "info")), "[Script Info]");
|
||||
}
|
||||
else if (lclass == "format") {
|
||||
// ohshi- ...
|
||||
// *FIXME* maybe ignore the actual data and just put some default stuff based on section?
|
||||
result = new AssEntry("Format: Auto4,Is,Broken", section);
|
||||
}
|
||||
else if (lclass == "style") {
|
||||
AssStyle *sty = new AssStyle;
|
||||
result = sty;
|
||||
|
@ -559,17 +536,11 @@ namespace Automation4 {
|
|||
if (it == lines.end() || (*it)->group != e->group) {
|
||||
// The new entry belongs to a group that doesn't exist yet, so
|
||||
// create it at the end of the file
|
||||
if (e->GetEntryData() != e->group) {
|
||||
// Add the header if the entry being added isn't a header
|
||||
lines.push_back(new AssEntry(e->group, e->group));
|
||||
}
|
||||
|
||||
lines.push_back(e);
|
||||
}
|
||||
else {
|
||||
// Append the entry to the end of the existing group
|
||||
++it;
|
||||
lines.insert(it, e);
|
||||
lines.insert(++it, e);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -528,7 +528,7 @@ static void delete_lines(agi::Context *c, wxString const& commit_message) {
|
|||
// lines, so make a new one
|
||||
if (!new_active) {
|
||||
new_active = new AssDialogue;
|
||||
c->ass->InsertDialogue(new_active);
|
||||
c->ass->InsertLine(new_active);
|
||||
}
|
||||
|
||||
c->ass->Commit(commit_message, AssFile::COMMIT_DIAG_ADDREM);
|
||||
|
|
|
@ -142,7 +142,7 @@ void DialogAttachments::AttachFile(wxFileDialog &diag, wxString const& group, wx
|
|||
delete newAttach;
|
||||
return;
|
||||
}
|
||||
ass->InsertAttachment(newAttach);
|
||||
ass->InsertLine(newAttach);
|
||||
}
|
||||
|
||||
ass->Commit(commit_msg, AssFile::COMMIT_ATTACHMENT);
|
||||
|
@ -211,30 +211,6 @@ void DialogAttachments::OnDelete(wxCommandEvent &) {
|
|||
i = listView->GetNextSelected(i);
|
||||
}
|
||||
|
||||
// Remove empty attachment sections in the file
|
||||
for (entryIter it = ass->Line.begin(); it != ass->Line.end(); ) {
|
||||
if (it->GetType() == ENTRY_BASE && (it->group == "[Fonts]" || it->group == "[Graphics]")) {
|
||||
wxString group = it->group;
|
||||
entryIter header = it;
|
||||
|
||||
bool has_attachments = false;
|
||||
for (++it; it != ass->Line.end() && it->group == group; ++it) {
|
||||
if (it->GetType() == ENTRY_ATTACHMENT) {
|
||||
has_attachments = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
// Empty group found, delete it
|
||||
if (!has_attachments) {
|
||||
while (header != it)
|
||||
delete &*header++;
|
||||
}
|
||||
}
|
||||
else
|
||||
++it;
|
||||
}
|
||||
|
||||
ass->Commit(_("remove attachment"), AssFile::COMMIT_ATTACHMENT);
|
||||
|
||||
UpdateList();
|
||||
|
|
|
@ -465,7 +465,7 @@ void DialogStyleEditor::Apply(bool apply, bool close) {
|
|||
if (store)
|
||||
store->push_back(style);
|
||||
else
|
||||
c->ass->InsertStyle(style);
|
||||
c->ass->InsertLine(style);
|
||||
is_new = false;
|
||||
}
|
||||
if (!store)
|
||||
|
|
|
@ -445,7 +445,7 @@ void DialogStyleManager::OnCopyToCurrent() {
|
|||
}
|
||||
}
|
||||
if (addStyle) {
|
||||
c->ass->InsertStyle(new AssStyle(*Store[selections[i]]));
|
||||
c->ass->InsertLine(new AssStyle(*Store[selections[i]]));
|
||||
copied.push_back(styleName);
|
||||
}
|
||||
}
|
||||
|
@ -477,7 +477,7 @@ void DialogStyleManager::CopyToClipboard(wxListBox *list, T const& v) {
|
|||
void DialogStyleManager::PasteToCurrent() {
|
||||
add_styles(
|
||||
std::bind(&AssFile::GetStyle, c->ass, _1),
|
||||
std::bind(&AssFile::InsertStyle, c->ass, _1));
|
||||
std::bind(&AssFile::InsertLine, c->ass, _1));
|
||||
|
||||
c->ass->Commit(_("style paste"), AssFile::COMMIT_STYLES);
|
||||
}
|
||||
|
@ -626,7 +626,7 @@ void DialogStyleManager::OnCurrentImport() {
|
|||
modified = true;
|
||||
AssStyle *tempStyle = new AssStyle;
|
||||
*tempStyle = *temp.GetStyle(styles[sel]);
|
||||
c->ass->InsertStyle(tempStyle);
|
||||
c->ass->InsertLine(tempStyle);
|
||||
}
|
||||
|
||||
// Update
|
||||
|
|
|
@ -60,7 +60,7 @@ SubtitlesPreview::SubtitlesPreview(wxWindow *parent, wxSize size, int winStyle,
|
|||
SetStyle(*style);
|
||||
|
||||
subFile->LoadDefault();
|
||||
subFile->InsertStyle(style);
|
||||
subFile->InsertLine(style);
|
||||
subFile->Line.push_back(*line);
|
||||
|
||||
SetSizeHints(size.GetWidth(), size.GetHeight(), -1, -1);
|
||||
|
|
|
@ -83,6 +83,36 @@ void AssSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxSt
|
|||
}
|
||||
}
|
||||
|
||||
static inline wxString header(wxString const& group, bool ssa) {
|
||||
if (ssa && group == "[V4+ Styles]")
|
||||
return "[V4 Styles]";
|
||||
return group;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
#define LINEBREAK "\r\n"
|
||||
#else
|
||||
#define LINEBREAK "\n"
|
||||
#endif
|
||||
|
||||
static inline wxString format(wxString const& group, bool ssa) {
|
||||
if (group == "[Events]") {
|
||||
if (ssa)
|
||||
return "Format: Marked, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" LINEBREAK;
|
||||
else
|
||||
return "Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text" LINEBREAK;
|
||||
}
|
||||
|
||||
if (group == "[v4+ styles]") {
|
||||
if (ssa)
|
||||
return "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, TertiaryColour, BackColour, Bold, Italic, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, AlphaLevel, Encoding" LINEBREAK;
|
||||
else
|
||||
return "Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding" LINEBREAK;
|
||||
}
|
||||
|
||||
return wxS("");
|
||||
}
|
||||
|
||||
void AssSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const {
|
||||
TextFileWriter file(filename, encoding);
|
||||
|
||||
|
@ -90,15 +120,20 @@ void AssSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename,
|
|||
file.WriteLineToFile("; http://www.aegisub.org/");
|
||||
|
||||
bool ssa = filename.Right(4).Lower() == ".ssa";
|
||||
wxString group;
|
||||
|
||||
wxString group = src->Line.front().group;
|
||||
for (auto const& line : src->Line) {
|
||||
// Add a blank line between each group
|
||||
if (line.group != group) {
|
||||
file.WriteLineToFile("");
|
||||
// Add a blank line between each group
|
||||
if (!group.empty())
|
||||
file.WriteLineToFile("");
|
||||
|
||||
file.WriteLineToFile(header(line.group, ssa));
|
||||
file.WriteLineToFile(format(line.group, ssa), false);
|
||||
|
||||
group = line.group;
|
||||
}
|
||||
|
||||
file.WriteLineToFile(ssa ? line.GetSSAText() : line.GetEntryData(), true);
|
||||
file.WriteLineToFile(ssa ? line.GetSSAText() : line.GetEntryData());
|
||||
}
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue