Fix crash on (auto)save when using CSRI and video is open
Calling AssFile::Save/Load from multiple threads (even on different objects) was not safe due to that is uses SubtitleFormat internally, which was inheriently thread-unsafe. To fix this, change SubtitleFormat's interface to support immutable implementations, and make all of the current implementations immutable. This isn't a perfect solution - making a subtitle format implemented in lua immutable would be rather difficult - so at some point in the future SubtitleFormat should probably be changed to a factory which returns new objects from GetReader/GetWriter. Originally committed to SVN as r6365.
This commit is contained in:
parent
d001d66b12
commit
15a4eca7ce
19 changed files with 221 additions and 313 deletions
aegisub/src
ass_file.cppsubtitle_format.cppsubtitle_format.hsubtitle_format_ass.cppsubtitle_format_ass.hsubtitle_format_encore.cppsubtitle_format_encore.hsubtitle_format_microdvd.cppsubtitle_format_microdvd.hsubtitle_format_mkv.cppsubtitle_format_mkv.hsubtitle_format_srt.cppsubtitle_format_srt.hsubtitle_format_transtation.cppsubtitle_format_transtation.hsubtitle_format_ttxt.cppsubtitle_format_ttxt.hsubtitle_format_txt.cppsubtitle_format_txt.h
|
@ -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;
|
||||
|
|
|
@ -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<AssEntry*>::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<AssDialogue*>(*cur)) {
|
||||
current->StripTags();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SubtitleFormat::ConvertNewlines(wxString const& newline, bool mergeLineBreaks) {
|
||||
for (std::list<AssEntry*>::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<AssDialogue*>(*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<AssEntry*>::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<AssDialogue*>(*it);
|
||||
if (!diag || (!diag->Comment && diag->Text.size()))
|
||||
++it;
|
||||
else {
|
||||
delete *it;
|
||||
Line->erase(it++);
|
||||
lines.erase(it++);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
void SubtitleFormat::StripNonDialogue() {
|
||||
for (std::list<AssEntry*>::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<AssDialogue*>(*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<AssEntry*>::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<AssDialogue*>(*cur);
|
||||
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(*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<AssEntry*>::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<AssEntry*>::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<AssDialogue*>(*cur);
|
||||
AssDialogue *nextdlg = dynamic_cast<AssDialogue*>(*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*> 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));
|
||||
}
|
||||
|
|
|
@ -45,7 +45,6 @@
|
|||
|
||||
#include <libaegisub/exception.h>
|
||||
|
||||
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<SubtitleFormat*> formats;
|
||||
|
||||
protected:
|
||||
std::list<AssEntry*> *Line;
|
||||
typedef std::list<AssEntry*> 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
|
||||
|
|
|
@ -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<AssEntry*>::iterator last = Line->end(); --last;
|
||||
wxString group = Line->front()->group;
|
||||
for (std::list<AssEntry*>::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("");
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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<AssEntry*>::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<AssDialogue*>(*cur)) {
|
||||
++i;
|
||||
file.WriteLineToFile(wxString::Format("%i %s %s %s", i, ft.ToSMPTE(current->Start, sep), ft.ToSMPTE(current->End, sep), current->Text));
|
||||
}
|
||||
}
|
||||
|
||||
ClearCopy();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -36,13 +36,15 @@
|
|||
|
||||
#include "config.h"
|
||||
|
||||
#include "subtitle_format_microdvd.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/regex.h>
|
||||
#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<AssEntry*>::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<AssDialogue*>(*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();
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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);
|
||||
}
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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 <http://devel.aegisub.org/wiki/SubtitleFormats/SRT>
|
||||
|
||||
|
@ -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<AssEntry*>::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<AssDialogue*>(*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<char, bool> tag_states;
|
||||
tag_states['i'] = false;
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -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<AssEntry*>::iterator it = Line->begin(); it != Line->end(); ++it) {
|
||||
for (std::list<AssEntry*>::iterator it = copy.Line.begin(); it != copy.Line.end(); ++it) {
|
||||
AssDialogue *cur = dynamic_cast<AssDialogue*>(*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";
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
|
@ -38,6 +38,10 @@
|
|||
|
||||
#include "subtitle_format_ttxt.h"
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/xml/xml.h>
|
||||
#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;i<text.Length();i++) {
|
||||
if (text[i] == '\'') {
|
||||
if (!in && !first) finalText += "\\N";
|
||||
first = false;
|
||||
in = !in;
|
||||
}
|
||||
else if (in) finalText += text[i];
|
||||
// Create dialogue
|
||||
AssDialogue *diag = new AssDialogue;
|
||||
diag->Start = 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<AssEntry*>::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<AssDialogue*>(*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<AssEntry*>::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<AssDialogue*>(*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);
|
||||
}
|
||||
|
|
|
@ -34,14 +34,10 @@
|
|||
/// @ingroup subtitle_io
|
||||
///
|
||||
|
||||
#ifndef AGI_PRE
|
||||
#include <wx/xml/xml.h>
|
||||
#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;
|
||||
};
|
||||
|
|
|
@ -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<AssEntry*>::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<AssDialogue*>(*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<AssEntry*>::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<AssDialogue*>(*l);
|
||||
|
||||
if (dia) {
|
||||
|
|
|
@ -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;
|
||||
};
|
||||
|
|
Loading…
Reference in a new issue