diff --git a/aegisub/src/ass_file.cpp b/aegisub/src/ass_file.cpp index 4cadbbb3d..99350b750 100644 --- a/aegisub/src/ass_file.cpp +++ b/aegisub/src/ass_file.cpp @@ -88,7 +88,7 @@ void AssFile::Load(const wxString &_filename,wxString charset,bool addToRecent) } // Get proper format reader - SubtitleFormat *reader = SubtitleFormat::GetReader(_filename); + const SubtitleFormat *reader = SubtitleFormat::GetReader(_filename); if (!reader) { wxMessageBox("Unknown file type","Error loading file",wxICON_ERROR | wxOK); @@ -97,8 +97,7 @@ void AssFile::Load(const wxString &_filename,wxString charset,bool addToRecent) // Read file AssFile temp; - reader->SetTarget(&temp); - reader->ReadFile(_filename,charset); + reader->ReadFile(&temp, _filename, charset); swap(temp); } catch (agi::UserCancelException const&) { @@ -156,7 +155,7 @@ void AssFile::Load(const wxString &_filename,wxString charset,bool addToRecent) } void AssFile::Save(wxString filename, bool setfilename, bool addToRecent, wxString encoding) { - SubtitleFormat *writer = SubtitleFormat::GetWriter(filename); + const SubtitleFormat *writer = SubtitleFormat::GetWriter(filename); if (!writer) throw "Unknown file type."; @@ -168,8 +167,7 @@ void AssFile::Save(wxString filename, bool setfilename, bool addToRecent, wxStri FileSave(); - writer->SetTarget(this); - writer->WriteFile(filename, encoding); + writer->WriteFile(this, filename, encoding); if (addToRecent) { AddToRecent(filename); @@ -229,8 +227,7 @@ bool AssFile::CanSave() { if (ext == ".txt") return false; // Check if it's a known extension - SubtitleFormat *writer = SubtitleFormat::GetWriter(filename); - if (!writer) return false; + if (!SubtitleFormat::GetWriter(filename)) return false; // Scan through the lines AssStyle defstyle; diff --git a/aegisub/src/subtitle_format.cpp b/aegisub/src/subtitle_format.cpp index 8ea59c106..345208bd4 100644 --- a/aegisub/src/subtitle_format.cpp +++ b/aegisub/src/subtitle_format.cpp @@ -59,8 +59,6 @@ using namespace std::tr1::placeholders; SubtitleFormat::SubtitleFormat(wxString const& name) : name(name) -, isCopy(0) -, Line(0) { formats.push_back(this); } @@ -69,12 +67,6 @@ SubtitleFormat::~SubtitleFormat() { formats.remove(this); } -void SubtitleFormat::SetTarget(AssFile *file) { - ClearCopy(); - Line = file ? &file->Line : 0; - assFile = file; -} - bool SubtitleFormat::CanReadFile(wxString const& filename) const { return GetReadWildcards().Index(filename.AfterLast('.'), false) != wxNOT_FOUND; } @@ -83,33 +75,8 @@ bool SubtitleFormat::CanWriteFile(wxString const& filename) const { return GetWriteWildcards().Index(filename.AfterLast('.'), false) != wxNOT_FOUND; } -void SubtitleFormat::CreateCopy() { - SetTarget(new AssFile(*assFile)); - isCopy = true; -} - -void SubtitleFormat::ClearCopy() { - if (isCopy) { - delete assFile; - assFile = NULL; - isCopy = false; - } -} - -void SubtitleFormat::Clear() { - assFile->Clear(); -} - -void SubtitleFormat::LoadDefault(bool defline) { - assFile->LoadDefault(defline); -} - -void SubtitleFormat::AddLine(wxString data, int *version, AssAttachment **attach) { - assFile->AddLine(data, version, attach); -} - /// @brief Ask the user to enter the FPS -FractionalTime SubtitleFormat::AskForFPS(bool showSMPTE) { +FractionalTime SubtitleFormat::AskForFPS(bool showSMPTE) const { wxArrayString choices; bool drop = false; @@ -171,20 +138,16 @@ FractionalTime SubtitleFormat::AskForFPS(bool showSMPTE) { return FractionalTime(fps, drop); } -void SubtitleFormat::SortLines() { - AssFile::Sort(*Line); -} - -void SubtitleFormat::StripTags() { - for (std::list::iterator cur = Line->begin(); cur != Line->end(); ++cur) { +void SubtitleFormat::StripTags(LineList &lines) const { + for (LineList::iterator cur = lines.begin(); cur != lines.end(); ++cur) { if (AssDialogue *current = dynamic_cast(*cur)) { current->StripTags(); } } } -void SubtitleFormat::ConvertNewlines(wxString const& newline, bool mergeLineBreaks) { - for (std::list::iterator cur = Line->begin(); cur != Line->end(); ++cur) { +void SubtitleFormat::ConvertNewlines(LineList &lines, wxString const& newline, bool mergeLineBreaks) const { + for (LineList::iterator cur = lines.begin(); cur != lines.end(); ++cur) { if (AssDialogue *current = dynamic_cast(*cur)) { current->Text.Replace("\\h", " "); current->Text.Replace("\\n", newline); @@ -196,25 +159,25 @@ void SubtitleFormat::ConvertNewlines(wxString const& newline, bool mergeLineBrea } } -void SubtitleFormat::StripComments() { - for (std::list::iterator it = Line->begin(); it != Line->end(); ) { +void SubtitleFormat::StripComments(LineList &lines) const { + for (LineList::iterator it = lines.begin(); it != lines.end(); ) { AssDialogue *diag = dynamic_cast(*it); if (!diag || (!diag->Comment && diag->Text.size())) ++it; else { delete *it; - Line->erase(it++); + lines.erase(it++); } } } -void SubtitleFormat::StripNonDialogue() { - for (std::list::iterator it = Line->begin(); it != Line->end(); ) { +void SubtitleFormat::StripNonDialogue(LineList &lines) const { + for (LineList::iterator it = lines.begin(); it != lines.end(); ) { if (dynamic_cast(*it)) ++it; else { delete *it; - Line->erase(it++); + lines.erase(it++); } } } @@ -227,11 +190,11 @@ static bool dialog_start_lt(AssEntry *pos, AssDialogue *to_insert) { /// @brief Split and merge lines so there are no overlapping lines /// /// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge -void SubtitleFormat::RecombineOverlaps() { - std::list::iterator cur, next = Line->begin(); +void SubtitleFormat::RecombineOverlaps(LineList &lines) const { + LineList::iterator cur, next = lines.begin(); cur = next++; - for (; next != Line->end(); cur = next++) { + for (; next != lines.end(); cur = next++) { AssDialogue *prevdlg = dynamic_cast(*cur); AssDialogue *curdlg = dynamic_cast(*next); @@ -240,15 +203,15 @@ void SubtitleFormat::RecombineOverlaps() { // Use names like in the algorithm description and prepare for erasing // old dialogues from the list - std::list::iterator prev = cur; + LineList::iterator prev = cur; cur = next; next++; // std::list::insert() inserts items before the given iterator, so // we need 'next' for inserting. 'prev' and 'cur' can safely be erased // from the list now. - Line->erase(prev); - Line->erase(cur); + lines.erase(prev); + lines.erase(cur); //Is there an A part before the overlap? if (curdlg->Start > prevdlg->Start) { @@ -258,7 +221,7 @@ void SubtitleFormat::RecombineOverlaps() { newdlg->End = curdlg->Start; newdlg->Text = prevdlg->Text; - Line->insert(find_if(next, Line->end(), bind(dialog_start_lt, _1, newdlg)), newdlg); + lines.insert(find_if(next, lines.end(), bind(dialog_start_lt, _1, newdlg)), newdlg); } // Overlapping A+B part @@ -269,7 +232,7 @@ void SubtitleFormat::RecombineOverlaps() { // Put an ASS format hard linewrap between lines newdlg->Text = curdlg->Text + "\\N" + prevdlg->Text; - Line->insert(find_if(next, Line->end(), bind(dialog_start_lt, _1, newdlg)), newdlg); + lines.insert(find_if(next, lines.end(), bind(dialog_start_lt, _1, newdlg)), newdlg); } // Is there an A part after the overlap? @@ -280,7 +243,7 @@ void SubtitleFormat::RecombineOverlaps() { newdlg->End = prevdlg->End; newdlg->Text = prevdlg->Text; - Line->insert(find_if(next, Line->end(), bind(dialog_start_lt, _1, newdlg)), newdlg); + lines.insert(find_if(next, lines.end(), bind(dialog_start_lt, _1, newdlg)), newdlg); } // Is there a B part after the overlap? @@ -291,7 +254,7 @@ void SubtitleFormat::RecombineOverlaps() { newdlg->End = curdlg->End; newdlg->Text = curdlg->Text; - Line->insert(find_if(next, Line->end(), bind(dialog_start_lt, _1, newdlg)), newdlg); + lines.insert(find_if(next, lines.end(), bind(dialog_start_lt, _1, newdlg)), newdlg); } next--; @@ -299,11 +262,11 @@ void SubtitleFormat::RecombineOverlaps() { } /// @brief Merge identical lines that follow each other -void SubtitleFormat::MergeIdentical() { - std::list::iterator cur, next = Line->begin(); +void SubtitleFormat::MergeIdentical(LineList &lines) const { + LineList::iterator cur, next = lines.begin(); cur = next++; - for (; next != Line->end(); cur = next++) { + for (; next != lines.end(); cur = next++) { AssDialogue *curdlg = dynamic_cast(*cur); AssDialogue *nextdlg = dynamic_cast(*next); @@ -314,7 +277,7 @@ void SubtitleFormat::MergeIdentical() { // Remove duplicate line delete *cur; - Line->erase(cur); + lines.erase(cur); } } } @@ -323,14 +286,14 @@ std::list SubtitleFormat::formats; void SubtitleFormat::LoadFormats() { if (formats.empty()) { - new ASSSubtitleFormat(); - new EncoreSubtitleFormat(); - new MKVSubtitleFormat(); - new MicroDVDSubtitleFormat(); - new SRTSubtitleFormat(); - new TTXTSubtitleFormat(); - new TXTSubtitleFormat(); - new TranStationSubtitleFormat(); + new ASSSubtitleFormat; + new EncoreSubtitleFormat; + new MKVSubtitleFormat; + new MicroDVDSubtitleFormat; + new SRTSubtitleFormat; + new TTXTSubtitleFormat; + new TXTSubtitleFormat; + new TranStationSubtitleFormat; } } @@ -347,12 +310,12 @@ SubtitleFormat *find_or_null(Cont &container, Pred pred) { return *it; } -SubtitleFormat *SubtitleFormat::GetReader(wxString const& filename) { +const SubtitleFormat *SubtitleFormat::GetReader(wxString const& filename) { LoadFormats(); return find_or_null(formats, bind(&SubtitleFormat::CanReadFile, _1, filename)); } -SubtitleFormat *SubtitleFormat::GetWriter(wxString const& filename) { +const SubtitleFormat *SubtitleFormat::GetWriter(wxString const& filename) { LoadFormats(); return find_or_null(formats, bind(&SubtitleFormat::CanWriteFile, _1, filename)); } diff --git a/aegisub/src/subtitle_format.h b/aegisub/src/subtitle_format.h index 8a489b663..9c7262bfb 100644 --- a/aegisub/src/subtitle_format.h +++ b/aegisub/src/subtitle_format.h @@ -45,7 +45,6 @@ #include -class AssAttachment; class AssEntry; class AssFile; class FractionalTime; @@ -57,8 +56,6 @@ class FractionalTime; /// DOCME class SubtitleFormat { wxString name; - bool isCopy; - AssFile *assFile; /// Get this format's wildcards for a load dialog virtual wxArrayString GetReadWildcards() const { return wxArrayString(); } @@ -69,47 +66,28 @@ class SubtitleFormat { static std::list formats; protected: - std::list *Line; + typedef std::list LineList; - /// Copy the input subtitles file; must be called before making any changes - void CreateCopy(); - /// Delete the subtitle file if we own it; should be called after processing - /// if CreateCopy was used - void ClearCopy(); - /// Sort the lines by start time - void SortLines(); /// Strip override tags - void StripTags(); + void StripTags(LineList &lines) const; /// Convert newlines to the specified character(s) /// @param lineEnd newline character(s) /// @param mergeLineBreaks Should multiple consecutive line breaks be merged into one? - void ConvertNewlines(wxString const& newline, bool mergeLineBreaks = true); + void ConvertNewlines(LineList &lines, wxString const& newline, bool mergeLineBreaks = true) const; /// Remove All commented and empty lines - void StripComments(); + void StripComments(LineList &lines) const; /// Remove everything but the dialogue lines - void StripNonDialogue(); + void StripNonDialogue(LineList &lines) const; /// @brief Split and merge lines so there are no overlapping lines /// /// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge - void RecombineOverlaps(); + void RecombineOverlaps(LineList &lines) const; /// Merge sequential identical lines - void MergeIdentical(); + void MergeIdentical(LineList &lines) const; - /// Clear the subtitle file - void Clear(); - /// Load the default file - /// @param defline Add a blank line? - void LoadDefault(bool defline=true); - - AssFile *GetAssFile() { return assFile; } - /// Add a line to the output file - /// @param data Full text of ASS line - /// @param[in,out] version ASS version the line was parsed as - /// @param[in,out] attach Accumulator for attachment parsing - void AddLine(wxString data, int *version, AssAttachment **attach); /// Prompt the user for a framerate to use /// @param showSMPTE Include SMPTE as an option? - FractionalTime AskForFPS(bool showSMPTE=false); + FractionalTime AskForFPS(bool showSMPTE=false) const; public: /// Constructor @@ -120,42 +98,41 @@ public: /// @note Automatically unregisters the format virtual ~SubtitleFormat(); - /// Set the target file to write - void SetTarget(AssFile *file); - /// Get this format's name wxString GetName() const { return name; } /// @brief Check if the given file can be read by this format /// - /// Default implemention simply checks if the file's extension is in the + /// Default implement ion simply checks if the file's extension is in the /// format's wildcard list virtual bool CanReadFile(wxString const& filename) const; /// @brief Check if the given file can be written by this format /// - /// Default implemention simply checks if the file's extension is in the + /// Default implement ion simply checks if the file's extension is in the /// format's wildcard list virtual bool CanWriteFile(wxString const& filename) const; /// Load a subtitle file + /// @param[out] target Destination to read lines into /// @param filename File to load /// @param forceEncoding Encoding to use or empty string for default - virtual void ReadFile(wxString const& filename, wxString const& forceEncoding="") { } + virtual void ReadFile(AssFile *target, wxString const& filename, wxString const& forceEncoding="") const { } /// Save a subtitle file + /// @param src Data to write /// @param filename File to write to /// @param forceEncoding Encoding to use or empty string for default - virtual void WriteFile(wxString const& filename, wxString const& encoding="") { } + virtual void WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding="") const { } /// Get the wildcards for a save or load dialog /// @param mode 0: load 1: save static wxString GetWildcards(int mode); /// Get a subtitle format that can read the given file or NULL if none can - static SubtitleFormat *GetReader(wxString const& filename); + static const SubtitleFormat *GetReader(wxString const& filename); /// Get a subtitle format that can write the given file or NULL if none can - static SubtitleFormat *GetWriter(wxString const& filename); + static const SubtitleFormat *GetWriter(wxString const& filename); /// Initialize subtitle formats static void LoadFormats(); /// Deinitialize subtitle formats diff --git a/aegisub/src/subtitle_format_ass.cpp b/aegisub/src/subtitle_format_ass.cpp index 465c7734a..ed5aa8857 100644 --- a/aegisub/src/subtitle_format_ass.cpp +++ b/aegisub/src/subtitle_format_ass.cpp @@ -39,6 +39,7 @@ #include "subtitle_format_ass.h" #include "ass_dialogue.h" +#include "ass_file.h" #include "compat.h" #include "text_file_reader.h" #include "text_file_writer.h" @@ -64,9 +65,11 @@ wxArrayString ASSSubtitleFormat::GetWriteWildcards() const { return formats; } -void ASSSubtitleFormat::ReadFile(wxString const& filename, wxString const& encoding) { +void ASSSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxString const& encoding) const { using namespace std; + target->Clear(); + TextFileReader file(filename, encoding); int version = filename.Right(4).Lower() != ".ssa"; AssAttachment *attach = 0; @@ -74,22 +77,22 @@ void ASSSubtitleFormat::ReadFile(wxString const& filename, wxString const& encod while (file.HasMoreLines()) { wxString line = file.ReadLineFromFile(); try { - AddLine(line, &version, &attach); + target->AddLine(line, &version, &attach); } catch (const char *err) { - Clear(); + target->Clear(); throw AssParseError("Error processing line: " + STD_STR(line) + ": " + err, 0); } } } -void ASSSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) { +void ASSSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const { TextFileWriter file(filename, encoding); bool ssa = filename.Right(4).Lower() == ".ssa"; - std::list::iterator last = Line->end(); --last; - wxString group = Line->front()->group; - for (std::list::iterator cur=Line->begin(); cur!=Line->end(); ++cur) { + LineList::const_iterator last = src->Line.end(); --last; + wxString group = src->Line.front()->group; + for (LineList::const_iterator cur = src->Line.begin(); cur != src->Line.end(); ++cur) { // Add a blank line between each group if ((*cur)->group != group) { file.WriteLineToFile(""); diff --git a/aegisub/src/subtitle_format_ass.h b/aegisub/src/subtitle_format_ass.h index 53317ebca..a0eb82af1 100644 --- a/aegisub/src/subtitle_format_ass.h +++ b/aegisub/src/subtitle_format_ass.h @@ -48,6 +48,6 @@ public: wxArrayString GetReadWildcards() const; wxArrayString GetWriteWildcards() const; - void ReadFile(wxString const& filename, wxString const& forceEncoding); - void WriteFile(wxString const& filename, wxString const& encoding); + void ReadFile(AssFile *target, wxString const& filename, wxString const& forceEncoding) const; + void WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const; }; diff --git a/aegisub/src/subtitle_format_encore.cpp b/aegisub/src/subtitle_format_encore.cpp index 3641f92dc..d1f1ed76b 100644 --- a/aegisub/src/subtitle_format_encore.cpp +++ b/aegisub/src/subtitle_format_encore.cpp @@ -39,6 +39,7 @@ #include "subtitle_format_encore.h" #include "ass_dialogue.h" +#include "ass_file.h" #include "text_file_writer.h" EncoreSubtitleFormat::EncoreSubtitleFormat() @@ -52,20 +53,20 @@ wxArrayString EncoreSubtitleFormat::GetWriteWildcards() const { return formats; } -void EncoreSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) { +void EncoreSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const { FractionalTime ft = AskForFPS(true); if (!ft.FPS().IsLoaded()) return; TextFileWriter file(filename, encoding); // Convert to encore - CreateCopy(); - SortLines(); - StripComments(); - RecombineOverlaps(); - MergeIdentical(); - StripTags(); - ConvertNewlines("\r\n"); + AssFile copy(*src); + copy.Sort(); + StripComments(copy.Line); + RecombineOverlaps(copy.Line); + MergeIdentical(copy.Line); + StripTags(copy.Line); + ConvertNewlines(copy.Line, "\r\n"); // Write lines int i = 0; @@ -73,12 +74,10 @@ void EncoreSubtitleFormat::WriteFile(wxString const& filename, wxString const& e // Encore wants ; instead of : if we're dealing with NTSC dropframe stuff char sep = ft.IsDrop() ? ';' : ':'; - for (std::list::iterator cur=Line->begin();cur!=Line->end();cur++) { + for (LineList::const_iterator cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) { if (AssDialogue *current = dynamic_cast(*cur)) { ++i; file.WriteLineToFile(wxString::Format("%i %s %s %s", i, ft.ToSMPTE(current->Start, sep), ft.ToSMPTE(current->End, sep), current->Text)); } } - - ClearCopy(); } diff --git a/aegisub/src/subtitle_format_encore.h b/aegisub/src/subtitle_format_encore.h index 06c8a81ad..552297405 100644 --- a/aegisub/src/subtitle_format_encore.h +++ b/aegisub/src/subtitle_format_encore.h @@ -46,5 +46,5 @@ class EncoreSubtitleFormat : public SubtitleFormat { public: EncoreSubtitleFormat(); wxArrayString GetWriteWildcards() const; - void WriteFile(wxString const& filename, wxString const& encoding); + void WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const; }; diff --git a/aegisub/src/subtitle_format_microdvd.cpp b/aegisub/src/subtitle_format_microdvd.cpp index 593cb224e..a78c38422 100644 --- a/aegisub/src/subtitle_format_microdvd.cpp +++ b/aegisub/src/subtitle_format_microdvd.cpp @@ -36,13 +36,15 @@ #include "config.h" +#include "subtitle_format_microdvd.h" + #ifndef AGI_PRE #include #endif #include "ass_dialogue.h" +#include "ass_file.h" #include "ass_time.h" -#include "subtitle_format_microdvd.h" #include "text_file_reader.h" #include "text_file_writer.h" #include "video_context.h" @@ -76,11 +78,11 @@ bool MicroDVDSubtitleFormat::CanReadFile(wxString const& filename) const { return false; } -void MicroDVDSubtitleFormat::ReadFile(wxString const& filename, wxString const& forceEncoding) { +void MicroDVDSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxString const& encoding) const { TextFileReader file(filename); wxRegEx exp("^[\\{\\[]([0-9]+)[\\}\\]][\\{\\[]([0-9]+)[\\}\\]](.*)$", wxRE_ADVANCED); - LoadDefault(false); + target->LoadDefault(false); agi::vfr::Framerate fps; @@ -117,22 +119,22 @@ void MicroDVDSubtitleFormat::ReadFile(wxString const& filename, wxString const& diag->Start = fps.TimeAtFrame(f1, agi::vfr::START); diag->End = fps.TimeAtFrame(f2, agi::vfr::END); diag->Text = text; - Line->push_back(diag); + target->Line.push_back(diag); } } } -void MicroDVDSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) { +void MicroDVDSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const { agi::vfr::Framerate fps = AskForFPS().FPS(); if (!fps.IsLoaded()) return; - CreateCopy(); - SortLines(); - StripComments(); - RecombineOverlaps(); - MergeIdentical(); - StripTags(); - ConvertNewlines("|"); + AssFile copy(*src); + copy.Sort(); + StripComments(copy.Line); + RecombineOverlaps(copy.Line); + MergeIdentical(copy.Line); + StripTags(copy.Line); + ConvertNewlines(copy.Line, "|"); TextFileWriter file(filename, encoding); @@ -142,7 +144,7 @@ void MicroDVDSubtitleFormat::WriteFile(wxString const& filename, wxString const& } // Write lines - for (std::list::iterator cur=Line->begin();cur!=Line->end();cur++) { + for (LineList::const_iterator cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) { if (AssDialogue *current = dynamic_cast(*cur)) { int start = fps.FrameAtTime(current->Start, agi::vfr::START); int end = fps.FrameAtTime(current->End, agi::vfr::END); @@ -150,6 +152,4 @@ void MicroDVDSubtitleFormat::WriteFile(wxString const& filename, wxString const& file.WriteLineToFile(wxString::Format("{%i}{%i}%s", start, end, current->Text)); } } - - ClearCopy(); } diff --git a/aegisub/src/subtitle_format_microdvd.h b/aegisub/src/subtitle_format_microdvd.h index 7e311c115..f6709449b 100644 --- a/aegisub/src/subtitle_format_microdvd.h +++ b/aegisub/src/subtitle_format_microdvd.h @@ -49,7 +49,7 @@ public: wxArrayString GetWriteWildcards() const; bool CanReadFile(wxString const& filename) const; - void ReadFile(wxString const& filename, wxString const& forceEncoding); + void ReadFile(AssFile *target, wxString const& filename, wxString const& forceEncoding) const; - void WriteFile(wxString const& filename, wxString const& encoding); + void WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const; }; diff --git a/aegisub/src/subtitle_format_mkv.cpp b/aegisub/src/subtitle_format_mkv.cpp index 0babc37a2..2d04e3b7e 100644 --- a/aegisub/src/subtitle_format_mkv.cpp +++ b/aegisub/src/subtitle_format_mkv.cpp @@ -53,6 +53,6 @@ wxArrayString MKVSubtitleFormat::GetReadWildcards() const { return formats; } -void MKVSubtitleFormat::ReadFile(wxString const& filename, wxString const&) { - MatroskaWrapper::GetSubtitles(filename, GetAssFile()); +void MKVSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxString const&) const { + MatroskaWrapper::GetSubtitles(filename, target); } diff --git a/aegisub/src/subtitle_format_mkv.h b/aegisub/src/subtitle_format_mkv.h index cb6957fb9..6042e1369 100644 --- a/aegisub/src/subtitle_format_mkv.h +++ b/aegisub/src/subtitle_format_mkv.h @@ -46,5 +46,5 @@ public: MKVSubtitleFormat(); wxArrayString GetReadWildcards() const; - void ReadFile(wxString const& filename, wxString const& forceEncoding); + void ReadFile(AssFile *target, wxString const& filename, wxString const& forceEncoding) const; }; diff --git a/aegisub/src/subtitle_format_srt.cpp b/aegisub/src/subtitle_format_srt.cpp index 45564ad47..2d99f1376 100644 --- a/aegisub/src/subtitle_format_srt.cpp +++ b/aegisub/src/subtitle_format_srt.cpp @@ -375,11 +375,11 @@ wxArrayString SRTSubtitleFormat::GetWriteWildcards() const { return GetReadWildcards(); } -void SRTSubtitleFormat::ReadFile(wxString const& filename, wxString const& encoding) { +void SRTSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxString const& encoding) const { using namespace std; TextFileReader file(filename, encoding); - LoadDefault(false); + target->LoadDefault(false); // See parsing algorithm at @@ -433,7 +433,7 @@ found_timestamps: line->Start = ReadSRTTime(timestamp_regex.GetMatch(text_line, 1)); line->End = ReadSRTTime(timestamp_regex.GetMatch(text_line, 2)); // store pointer to subtitle, we'll continue working on it - Line->push_back(line); + target->Line.push_back(line); // next we're reading the text state = 3; break; @@ -496,20 +496,20 @@ found_timestamps: line->Text = tag_parser.ToAss(line->Text); } -void SRTSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) { - TextFileWriter file(filename,encoding); +void SRTSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const { + TextFileWriter file(filename, encoding); // Convert to SRT - CreateCopy(); - SortLines(); - StripComments(); - RecombineOverlaps(); - MergeIdentical(); - ConvertNewlines("\r\n", false); + AssFile copy(*src); + copy.Sort(); + StripComments(copy.Line); + RecombineOverlaps(copy.Line); + MergeIdentical(copy.Line); + ConvertNewlines(copy.Line, "\r\n", false); // Write lines int i=1; - for (std::list::iterator cur = Line->begin(); cur != Line->end(); ++cur) { + for (LineList::const_iterator cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) { if (AssDialogue *current = dynamic_cast(*cur)) { file.WriteLineToFile(wxString::Format("%d", i++)); file.WriteLineToFile(WriteSRTTime(current->Start) + " --> " + WriteSRTTime(current->End)); @@ -517,11 +517,9 @@ void SRTSubtitleFormat::WriteFile(wxString const& filename, wxString const& enco file.WriteLineToFile(""); } } - - ClearCopy(); } -wxString SRTSubtitleFormat::ConvertTags(AssDialogue *diag) { +wxString SRTSubtitleFormat::ConvertTags(AssDialogue *diag) const { wxString final; std::map tag_states; tag_states['i'] = false; diff --git a/aegisub/src/subtitle_format_srt.h b/aegisub/src/subtitle_format_srt.h index c7c1f13ae..dc6254cbe 100644 --- a/aegisub/src/subtitle_format_srt.h +++ b/aegisub/src/subtitle_format_srt.h @@ -42,12 +42,12 @@ /// /// DOCME class SRTSubtitleFormat : public SubtitleFormat { - wxString ConvertTags(AssDialogue *diag); + wxString ConvertTags(AssDialogue *diag) const; public: SRTSubtitleFormat(); wxArrayString GetReadWildcards() const; wxArrayString GetWriteWildcards() const; - void ReadFile(wxString const& filename, wxString const& forceEncoding); - void WriteFile(wxString const& filename, wxString const& encoding); + void ReadFile(AssFile *target, wxString const& filename, wxString const& forceEncoding) const; + void WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const; }; diff --git a/aegisub/src/subtitle_format_transtation.cpp b/aegisub/src/subtitle_format_transtation.cpp index d843e40e4..235ef149c 100644 --- a/aegisub/src/subtitle_format_transtation.cpp +++ b/aegisub/src/subtitle_format_transtation.cpp @@ -59,25 +59,25 @@ wxArrayString TranStationSubtitleFormat::GetWriteWildcards() const { return formats; } -void TranStationSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) { +void TranStationSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const { FractionalTime ft = AskForFPS(true); if (!ft.FPS().IsLoaded()) return; TextFileWriter file(filename, encoding); // Convert to TranStation - CreateCopy(); - SortLines(); - StripComments(); - RecombineOverlaps(); - MergeIdentical(); + AssFile copy(*src); + copy.Sort(); + StripComments(copy.Line); + RecombineOverlaps(copy.Line); + MergeIdentical(copy.Line); AssDialogue *prev = 0; - for (std::list::iterator it = Line->begin(); it != Line->end(); ++it) { + for (std::list::iterator it = copy.Line.begin(); it != copy.Line.end(); ++it) { AssDialogue *cur = dynamic_cast(*it); if (prev && cur) { - file.WriteLineToFile(ConvertLine(prev, &ft, cur->Start)); + file.WriteLineToFile(ConvertLine(©, prev, &ft, cur->Start)); file.WriteLineToFile(""); } @@ -87,19 +87,17 @@ void TranStationSubtitleFormat::WriteFile(wxString const& filename, wxString con // flush last line if (prev) - file.WriteLineToFile(ConvertLine(prev, &ft, -1)); + file.WriteLineToFile(ConvertLine(©, prev, &ft, -1)); // Every file must end with this line file.WriteLineToFile("SUB["); - - ClearCopy(); } -wxString TranStationSubtitleFormat::ConvertLine(AssDialogue *current, FractionalTime *ft, int nextl_start) { +wxString TranStationSubtitleFormat::ConvertLine(AssFile *file, AssDialogue *current, FractionalTime *ft, int nextl_start) const { int valign = 0; const char *halign = " "; // default is centered const char *type = "N"; // no special style - if (AssStyle *style = GetAssFile()->GetStyle(current->Style)) { + if (AssStyle *style = file->GetStyle(current->Style)) { if (style->alignment >= 4) valign = 4; if (style->alignment >= 7) valign = 9; if (style->alignment == 1 || style->alignment == 4 || style->alignment == 7) halign = "L"; diff --git a/aegisub/src/subtitle_format_transtation.h b/aegisub/src/subtitle_format_transtation.h index 122a2cea5..c253d3395 100644 --- a/aegisub/src/subtitle_format_transtation.h +++ b/aegisub/src/subtitle_format_transtation.h @@ -44,10 +44,10 @@ class AssDialogue; /// /// DOCME class TranStationSubtitleFormat : public SubtitleFormat { - wxString ConvertLine(AssDialogue *line, FractionalTime *ft, int nextl_start); + wxString ConvertLine(AssFile *file, AssDialogue *line, FractionalTime *ft, int nextl_start) const; public: TranStationSubtitleFormat(); wxArrayString GetWriteWildcards() const; - void WriteFile(wxString const& filename, wxString const& encoding); + void WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const; }; diff --git a/aegisub/src/subtitle_format_ttxt.cpp b/aegisub/src/subtitle_format_ttxt.cpp index ed224baf9..e897140c3 100644 --- a/aegisub/src/subtitle_format_ttxt.cpp +++ b/aegisub/src/subtitle_format_ttxt.cpp @@ -38,6 +38,10 @@ #include "subtitle_format_ttxt.h" +#ifndef AGI_PRE +#include +#endif + #include "ass_dialogue.h" #include "ass_file.h" #include "ass_time.h" @@ -61,8 +65,8 @@ wxArrayString TTXTSubtitleFormat::GetWriteWildcards() const { return GetReadWildcards(); } -void TTXTSubtitleFormat::ReadFile(wxString const& filename, wxString const& forceEncoding) { - LoadDefault(false); +void TTXTSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxString const& encoding) const { + target->LoadDefault(false); // Load XML document wxXmlDocument doc; @@ -73,106 +77,96 @@ void TTXTSubtitleFormat::ReadFile(wxString const& filename, wxString const& forc // Check version wxString verStr = doc.GetRoot()->GetAttribute("version", ""); - version = -1; - if (verStr == "1.0") version = 0; - else if (verStr == "1.1") version = 1; - else throw TTXTParseError("Unknown TTXT version: " + STD_STR(verStr), 0); + int version = -1; + if (verStr == "1.0") + version = 0; + else if (verStr == "1.1") + version = 1; + else + throw TTXTParseError("Unknown TTXT version: " + STD_STR(verStr), 0); // Get children - diag = NULL; - wxXmlNode *child = doc.GetRoot()->GetChildren(); + AssDialogue *diag = 0; int lines = 0; - while (child) { + for (wxXmlNode *child = doc.GetRoot()->GetChildren(); child; child = child->GetNext()) { // Line if (child->GetName() == "TextSample") { - if (ProcessLine(child)) lines++; + if (diag = ProcessLine(child, diag, version)) { + lines++; + target->Line.push_back(diag); + } } - // Header else if (child->GetName() == "TextStreamHeader") { ProcessHeader(child); } - - // Proceed to next child - child = child->GetNext(); } // No lines? - if (lines == 0) { - AssDialogue *line = new AssDialogue(); - line->group = "[Events]"; - line->Style = "Default"; - line->Start = 0; - line->End = 5000; - Line->push_back(line); - } + if (lines == 0) + target->Line.push_back(new AssDialogue); } -bool TTXTSubtitleFormat::ProcessLine(wxXmlNode *node) { +AssDialogue *TTXTSubtitleFormat::ProcessLine(wxXmlNode *node, AssDialogue *prev, int version) const { // Get time wxString sampleTime = node->GetAttribute("sampleTime", "00:00:00.000"); AssTime time; time.ParseASS(sampleTime); // Set end time of last line - if (diag) diag->End = time; - diag = NULL; + if (prev) + prev->End = time; // Get text wxString text; - if (version == 0) text = node->GetAttribute("text", ""); - else text = node->GetNodeContent(); + if (version == 0) + text = node->GetAttribute("text", ""); + else + text = node->GetNodeContent(); // Create line - if (!text.IsEmpty()) { - // Create dialogue - diag = new AssDialogue(); - diag->Start = time; - diag->End = 36000000-10; - diag->group = "[Events]"; - diag->Style = "Default"; - diag->Comment = false; + if (text.empty()) return 0; - // Process text for 1.0 - if (version == 0) { - wxString finalText; - finalText.Alloc(text.Length()); - bool in = false; - bool first = true; - for (size_t i=0;iStart = time; + diag->End = 36000000-10; + + // Process text for 1.0 + if (version == 0) { + wxString finalText; + finalText.reserve(text.size()); + bool in = false; + bool first = true; + for (size_t i = 0; i < text.size(); ++i) { + if (text[i] == '\'') { + if (!in && !first) finalText += "\\N"; + first = false; + in = !in; } - diag->Text = finalText; + else if (in) finalText += text[i]; } - - // Process text for 1.1 - else { - text.Replace("\r", ""); - text.Replace("\n", "\\N"); - diag->Text = text; - } - - // Insert dialogue - Line->push_back(diag); - return true; + diag->Text = finalText; } - else return false; + // Process text for 1.1 + else { + text.Replace("\r", ""); + text.Replace("\n", "\\N"); + diag->Text = text; + } + + return diag; } -void TTXTSubtitleFormat::ProcessHeader(wxXmlNode *node) { +void TTXTSubtitleFormat::ProcessHeader(wxXmlNode *node) const { // TODO } -void TTXTSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) { +void TTXTSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const { // Convert to TTXT - CreateCopy(); - ConvertToTTXT(); + AssFile copy(*src); + ConvertToTTXT(copy); // Create XML structure wxXmlDocument doc; @@ -184,28 +178,22 @@ void TTXTSubtitleFormat::WriteFile(wxString const& filename, wxString const& enc WriteHeader(root); // Create lines - int i=1; - using std::list; - prev = NULL; - for (list::iterator cur=Line->begin();cur!=Line->end();cur++) { + AssDialogue *prev = 0; + for (LineList::iterator cur = copy.Line.begin(); cur != copy.Line.end(); ++cur) { AssDialogue *current = dynamic_cast(*cur); if (current && !current->Comment) { - WriteLine(root, current); - i++; + WriteLine(root, prev, current); + prev = current; } else throw TTXTParseError("Unexpected line type in TTXT file", 0); } // Save XML - //prevNode->SetNext(NULL); doc.Save(filename); - - // Clear - ClearCopy(); } -void TTXTSubtitleFormat::WriteHeader(wxXmlNode *root) { +void TTXTSubtitleFormat::WriteHeader(wxXmlNode *root) const { // Write stream header wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextStreamHeader"); node->AddAttribute("width", "400"); @@ -255,7 +243,7 @@ void TTXTSubtitleFormat::WriteHeader(wxXmlNode *root) { root->AddChild(node); } -void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, AssDialogue *line) { +void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, AssDialogue *prev, AssDialogue *line) const { // If it doesn't start at the end of previous, add blank if (prev && prev->End != line->Start) { wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextSample"); @@ -271,22 +259,19 @@ void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, AssDialogue *line) { node->AddAttribute("xml:space", "preserve"); root->AddChild(node); node->AddChild(new wxXmlNode(wxXML_TEXT_NODE, "", line->Text)); - - // Set as previous - prev = line; } -void TTXTSubtitleFormat::ConvertToTTXT () { - SortLines(); - StripComments(); - RecombineOverlaps(); - MergeIdentical(); - StripTags(); - ConvertNewlines("\r\n"); +void TTXTSubtitleFormat::ConvertToTTXT(AssFile &file) const { + file.Sort(); + StripComments(file.Line); + RecombineOverlaps(file.Line); + MergeIdentical(file.Line); + StripTags(file.Line); + ConvertNewlines(file.Line, "\r\n"); // Find last line AssTime lastTime; - for (std::list::reverse_iterator cur=Line->rbegin();cur!=Line->rend();cur++) { + for (LineList::reverse_iterator cur = file.Line.rbegin(); cur != file.Line.rend(); ++cur) { if (AssDialogue *prev = dynamic_cast(*cur)) { lastTime = prev->End; break; @@ -294,11 +279,11 @@ void TTXTSubtitleFormat::ConvertToTTXT () { } // Insert blank line at the end - AssDialogue *diag = new AssDialogue(); + AssDialogue *diag = new AssDialogue; diag->Start = lastTime; diag->End = lastTime+OPT_GET("Timing/Default Duration")->GetInt(); diag->group = "[Events]"; diag->Style = "Default"; diag->Comment = false; - Line->push_back(diag); + file.Line.push_back(diag); } diff --git a/aegisub/src/subtitle_format_ttxt.h b/aegisub/src/subtitle_format_ttxt.h index d1819433b..7a20095be 100644 --- a/aegisub/src/subtitle_format_ttxt.h +++ b/aegisub/src/subtitle_format_ttxt.h @@ -34,14 +34,10 @@ /// @ingroup subtitle_io /// -#ifndef AGI_PRE -#include -#endif - #include "subtitle_format.h" class AssDialogue; - +class wxXmlNode; /// DOCME /// @class TTXTSubtitleFormat @@ -49,28 +45,19 @@ class AssDialogue; /// /// DOCME class TTXTSubtitleFormat : public SubtitleFormat { - /// DOCME - int version; + AssDialogue *ProcessLine(wxXmlNode *node, AssDialogue *prev, int version) const; + void ProcessHeader(wxXmlNode *node) const; - /// DOCME - AssDialogue *diag; + void WriteHeader(wxXmlNode *root) const; + void WriteLine(wxXmlNode *root, AssDialogue *prev, AssDialogue *line) const; - /// DOCME - AssDialogue *prev; - - bool ProcessLine(wxXmlNode *node); - void ProcessHeader(wxXmlNode *node); - - void WriteHeader(wxXmlNode *root); - void WriteLine(wxXmlNode *root, AssDialogue *line); - - void ConvertToTTXT(); + void ConvertToTTXT(AssFile &file) const; public: TTXTSubtitleFormat(); wxArrayString GetReadWildcards() const; wxArrayString GetWriteWildcards() const; - void ReadFile(wxString const& filename, wxString const& forceEncoding); - void WriteFile(wxString const& filename, wxString const& encoding); + void ReadFile(AssFile *target, wxString const& filename, wxString const& forceEncoding) const; + void WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const; }; diff --git a/aegisub/src/subtitle_format_txt.cpp b/aegisub/src/subtitle_format_txt.cpp index 408fd6ae7..445547c03 100644 --- a/aegisub/src/subtitle_format_txt.cpp +++ b/aegisub/src/subtitle_format_txt.cpp @@ -39,6 +39,7 @@ #include "subtitle_format_txt.h" #include "ass_dialogue.h" +#include "ass_file.h" #include "compat.h" #include "dialog_text_import.h" #include "main.h" @@ -66,14 +67,14 @@ bool TXTSubtitleFormat::CanWriteFile(wxString const& filename) const { return (filename.Right(4).Lower() == ".txt" && filename.Right(11).Lower() != ".encore.txt" && filename.Right(16).Lower() != ".transtation.txt"); } -void TXTSubtitleFormat::ReadFile(wxString const& filename, wxString const& encoding) { +void TXTSubtitleFormat::ReadFile(AssFile *target, wxString const& filename, wxString const& encoding) const { using namespace std; DialogTextImport dlg; if (dlg.ShowModal() == wxID_CANCEL) return; TextFileReader file(filename, encoding, false); - LoadDefault(false); + target->LoadDefault(false); wxString actor; wxString separator = lagi_wxString(OPT_GET("Tool/Import/Text/Actor Separator")->GetString()); @@ -123,7 +124,7 @@ void TXTSubtitleFormat::ReadFile(wxString const& filename, wxString const& encod line->End = 0; // Adds line - Line->push_back(line); + target->Line.push_back(line); lines++; } @@ -131,15 +132,15 @@ void TXTSubtitleFormat::ReadFile(wxString const& filename, wxString const& encod if (lines == 0) { AssDialogue *line = new AssDialogue; line->End = OPT_GET("Timing/Default Duration")->GetInt(); - Line->push_back(line); + target->Line.push_back(line); } } -void TXTSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) { +void TXTSubtitleFormat::WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const { size_t num_actor_names = 0, num_dialogue_lines = 0; // Detect number of lines with Actor field filled out - for (std::list::iterator l = Line->begin(); l != Line->end(); ++l) { + for (LineList::const_iterator l = src->Line.begin(); l != src->Line.end(); ++l) { AssDialogue *dia = dynamic_cast(*l); if (dia && !dia->Comment) { num_dialogue_lines++; @@ -156,7 +157,7 @@ void TXTSubtitleFormat::WriteFile(wxString const& filename, wxString const& enco file.WriteLineToFile(wxString("# Exported by Aegisub ") + GetAegisubShortVersionString()); // Write the file - for (std::list::iterator l = Line->begin(); l != Line->end(); ++l) { + for (LineList::const_iterator l = src->Line.begin(); l != src->Line.end(); ++l) { AssDialogue *dia = dynamic_cast(*l); if (dia) { diff --git a/aegisub/src/subtitle_format_txt.h b/aegisub/src/subtitle_format_txt.h index c8431fa20..f6cd22e03 100644 --- a/aegisub/src/subtitle_format_txt.h +++ b/aegisub/src/subtitle_format_txt.h @@ -48,6 +48,6 @@ public: wxArrayString GetWriteWildcards() const; bool CanWriteFile(wxString const& filename) const; - void ReadFile(wxString const& filename, wxString const& forceEncoding); - void WriteFile(wxString const& filename, wxString const& encoding); + void ReadFile(AssFile *target, wxString const& filename, wxString const& forceEncoding) const; + void WriteFile(const AssFile *src, wxString const& filename, wxString const& encoding) const; };