Clean up SubtitleFormat

Document all of the SubtitleFormat methods.

Add default implementations of CanReadFile and CanWriteFile that check
against the appropriate wildcard list.

Clean up and simplify a lot of very odd code.

Throw typed exceptions in all subtitle readers rather than strings.

Originally committed to SVN as r5617.
This commit is contained in:
Thomas Goyne 2011-09-28 19:44:53 +00:00
parent 156885b56d
commit 4ec507f814
22 changed files with 511 additions and 1182 deletions

View file

@ -104,16 +104,6 @@ void AssFile::Load(const wxString &_filename,wxString charset,bool addToRecent)
catch (agi::UserCancelException const&) { catch (agi::UserCancelException const&) {
return; return;
} }
catch (const char *except) {
wxMessageBox(except,"Error loading file",wxICON_ERROR | wxOK);
return;
}
catch (wxString &except) {
wxMessageBox(except,"Error loading file",wxICON_ERROR | wxOK);
return;
}
// Real exception // Real exception
catch (agi::Exception &e) { catch (agi::Exception &e) {
wxMessageBox(lagi_wxString(e.GetChainedMessage()), "Error loading file", wxICON_ERROR|wxOK); wxMessageBox(lagi_wxString(e.GetChainedMessage()), "Error loading file", wxICON_ERROR|wxOK);

View file

@ -360,6 +360,7 @@ namespace Automation4 {
/// ///
FeatureSubtitleFormat::FeatureSubtitleFormat(const wxString &_name, const wxString &_extension) FeatureSubtitleFormat::FeatureSubtitleFormat(const wxString &_name, const wxString &_extension)
: Feature(SCRIPTFEATURE_SUBFORMAT, _name) : Feature(SCRIPTFEATURE_SUBFORMAT, _name)
, SubtitleFormat(_name)
, extension(_extension) , extension(_extension)
{ {
// nothing to do // nothing to do

View file

@ -41,6 +41,7 @@
#include <wx/choicdlg.h> // Keep this last so wxUSE_CHOICEDLG is set. #include <wx/choicdlg.h> // Keep this last so wxUSE_CHOICEDLG is set.
#endif #endif
#include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "subtitle_format.h" #include "subtitle_format.h"
#include "subtitle_format_ass.h" #include "subtitle_format_ass.h"
@ -52,47 +53,42 @@
#include "subtitle_format_transtation.h" #include "subtitle_format_transtation.h"
#include "subtitle_format_ttxt.h" #include "subtitle_format_ttxt.h"
#include "subtitle_format_txt.h" #include "subtitle_format_txt.h"
#include "utils.h"
#include "video_context.h" #include "video_context.h"
/// @brief Constructor using namespace std::tr1::placeholders;
///
SubtitleFormat::SubtitleFormat() { SubtitleFormat::SubtitleFormat(wxString const& name)
Line = NULL; : name(name)
Register(); , isCopy(0)
isCopy = false; , Line(0)
{
formats.push_back(this);
} }
/// @brief Destructor SubtitleFormat::~SubtitleFormat() {
/// formats.remove(this);
SubtitleFormat::~SubtitleFormat () {
Remove();
} }
/// DOCME
std::list<SubtitleFormat*> SubtitleFormat::formats;
/// DOCME
bool SubtitleFormat::loaded = false;
/// @brief Set target
/// @param file
///
void SubtitleFormat::SetTarget(AssFile *file) { void SubtitleFormat::SetTarget(AssFile *file) {
ClearCopy(); ClearCopy();
if (!file) Line = NULL; Line = file ? &file->Line : 0;
else Line = &file->Line;
assFile = file; assFile = file;
} }
/// @brief Create copy bool SubtitleFormat::CanReadFile(wxString const& filename) const {
/// return GetReadWildcards().Index(filename.AfterLast('.'), false) != wxNOT_FOUND;
}
bool SubtitleFormat::CanWriteFile(wxString const& filename) const {
return GetWriteWildcards().Index(filename.AfterLast('.'), false) != wxNOT_FOUND;
}
void SubtitleFormat::CreateCopy() { void SubtitleFormat::CreateCopy() {
SetTarget(new AssFile(*assFile)); SetTarget(new AssFile(*assFile));
isCopy = true; isCopy = true;
} }
/// @brief Clear copy
///
void SubtitleFormat::ClearCopy() { void SubtitleFormat::ClearCopy() {
if (isCopy) { if (isCopy) {
delete assFile; delete assFile;
@ -101,184 +97,19 @@ void SubtitleFormat::ClearCopy() {
} }
} }
/// @brief Clear subtitles
///
void SubtitleFormat::Clear() { void SubtitleFormat::Clear() {
assFile->Clear(); assFile->Clear();
} }
/// @brief Load default
/// @param defline
///
void SubtitleFormat::LoadDefault(bool defline) { void SubtitleFormat::LoadDefault(bool defline) {
assFile->LoadDefault(defline); assFile->LoadDefault(defline);
} }
/// @brief Add line void SubtitleFormat::AddLine(wxString data, wxString group, int &version, wxString *outgroup) {
/// @param data assFile->AddLine(data, group, version, outgroup);
/// @param group
/// @param version
/// @param outgroup
void SubtitleFormat::AddLine(wxString data,wxString group,int &version,wxString *outgroup) {
assFile->AddLine(data,group,version,outgroup);
}
/// @brief Add formats
///
void SubtitleFormat::LoadFormats () {
if (!loaded) {
new ASSSubtitleFormat();
new SRTSubtitleFormat();
new TXTSubtitleFormat();
new TTXTSubtitleFormat();
new MicroDVDSubtitleFormat();
new MKVSubtitleFormat();
new EncoreSubtitleFormat();
new TranStationSubtitleFormat();
#ifdef _DEBUG
new DVDSubtitleFormat();
#endif
}
loaded = true;
}
/// @brief Destroy formats
///
void SubtitleFormat::DestroyFormats () {
std::list<SubtitleFormat*>::iterator cur;
for (cur=formats.begin();cur!=formats.end();cur = formats.begin()) {
delete *cur;
}
formats.clear();
}
/// @brief Get an appropriate reader
/// @param filename
/// @return
///
SubtitleFormat *SubtitleFormat::GetReader(wxString filename) {
LoadFormats();
std::list<SubtitleFormat*>::iterator cur;
SubtitleFormat *reader;
for (cur=formats.begin();cur!=formats.end();cur++) {
reader = *cur;
if (reader->CanReadFile(filename)) return reader;
}
return NULL;
}
/// @brief Get an appropriate writer
/// @param filename
/// @return
///
SubtitleFormat *SubtitleFormat::GetWriter(wxString filename) {
LoadFormats();
std::list<SubtitleFormat*>::iterator cur;
SubtitleFormat *writer;
for (cur=formats.begin();cur!=formats.end();cur++) {
writer = *cur;
if (writer->CanWriteFile(filename)) return writer;
}
return NULL;
}
/// @brief Register
/// @return
///
void SubtitleFormat::Register() {
std::list<SubtitleFormat*>::iterator cur;
for (cur=formats.begin();cur!=formats.end();cur++) {
if (*cur == this) return;
}
formats.push_back(this);
}
/// @brief Remove
/// @return
///
void SubtitleFormat::Remove() {
std::list<SubtitleFormat*>::iterator cur;
for (cur=formats.begin();cur!=formats.end();cur++) {
if (*cur == this) {
formats.erase(cur);
return;
}
}
}
/// @brief Get read wildcards
/// @return
///
wxArrayString SubtitleFormat::GetReadWildcards() {
return wxArrayString();
}
/// @brief Get write wildcards
/// @return
///
wxArrayString SubtitleFormat::GetWriteWildcards() {
return wxArrayString();
}
/// @brief Get wildcard list
/// @param mode
/// @return
///
wxString SubtitleFormat::GetWildcards(int mode) {
// Ensure it's loaded
LoadFormats();
// Variables
wxArrayString all;
wxArrayString cur;
wxString wild;
wxString final;
wxString temp1;
wxString temp2;
// For each format
std::list<SubtitleFormat*>::iterator curIter;
SubtitleFormat *format;
for (curIter=formats.begin();curIter!=formats.end();curIter++) {
// Get list
format = *curIter;
if (mode == 0) cur = format->GetReadWildcards();
else if (mode == 1) cur = format->GetWriteWildcards();
temp1.Clear();
temp2.Clear();
// Has wildcards
if (cur.Count()) {
// Process entries
for (unsigned int i=0;i<cur.Count();i++) {
wild = "*." + cur[i];
all.Add(wild);
temp1 += wild + ",";
temp2 += wild + ";";
}
// Assemble final name
final += format->GetName() + " (" + temp1.Left(temp1.Length()-1) + ")|" + temp2.Left(temp2.Length()-1) + "|";
}
}
// Add "all formats" list
temp1.Clear();
temp2.Clear();
for (unsigned int i=0;i<all.Count();i++) {
temp1 += all[i] + ",";
temp2 += all[i] + ";";
}
final = wxString(_("All Supported Formats")) + " (" + temp1.Left(temp1.Length()-1) + ")|" + temp2.Left(temp2.Length()-1) + "|" + final.Left(final.Length()-1);
// Return final list
return final;
} }
/// @brief Ask the user to enter the FPS /// @brief Ask the user to enter the FPS
/// @param showSMPTE
/// @return
///
SubtitleFormat::FPSRational SubtitleFormat::AskForFPS(bool showSMPTE) { SubtitleFormat::FPSRational SubtitleFormat::AskForFPS(bool showSMPTE) {
wxArrayString choices; wxArrayString choices;
FPSRational fps_rat; FPSRational fps_rat;
@ -290,8 +121,8 @@ SubtitleFormat::FPSRational SubtitleFormat::AskForFPS(bool showSMPTE) {
if (vidLoaded) { if (vidLoaded) {
wxString vidFPS; wxString vidFPS;
if (context->FPS().IsVFR()) vidFPS = "VFR"; if (context->FPS().IsVFR()) vidFPS = "VFR";
else vidFPS = wxString::Format("%.3f",context->FPS().FPS()); else vidFPS = wxString::Format("%.3f", context->FPS().FPS());
choices.Add(wxString::Format("From video (%s)",vidFPS)); choices.Add(wxString::Format("From video (%s)", vidFPS));
} }
// Standard FPS values // Standard FPS values
@ -310,7 +141,7 @@ SubtitleFormat::FPSRational SubtitleFormat::AskForFPS(bool showSMPTE) {
choices.Add(_("120.000 FPS")); choices.Add(_("120.000 FPS"));
// Ask // Ask
int choice = wxGetSingleChoiceIndex(_("Please choose the appropriate FPS for the subtitles:"),_("FPS"),choices); int choice = wxGetSingleChoiceIndex(_("Please choose the appropriate FPS for the subtitles:"), _("FPS"), choices);
if (choice == -1) { if (choice == -1) {
fps_rat.num = 0; fps_rat.num = 0;
fps_rat.den = 0; fps_rat.den = 0;
@ -364,191 +195,143 @@ SubtitleFormat::FPSRational SubtitleFormat::AskForFPS(bool showSMPTE) {
return fps_rat; return fps_rat;
} }
/// @brief Sort lines
///
void SubtitleFormat::SortLines() { void SubtitleFormat::SortLines() {
AssFile::Sort(*Line); AssFile::Sort(*Line);
} }
/// @brief Convert tags void SubtitleFormat::ConvertTags(int format, const wxString &lineEnd, bool mergeLineBreaks) {
/// @param format for (std::list<AssEntry*>::iterator cur = Line->begin(); cur != Line->end(); ++cur) {
/// @param lineEnd if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) {
///
void SubtitleFormat::ConvertTags(int format,const wxString &lineEnd,bool mergeLineBreaks) {
using std::list;
list<AssEntry*>::iterator next;
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
AssDialogue *current = dynamic_cast<AssDialogue*>(*cur);
if (current) {
// Strip tags // Strip tags
if (format == 1) current->StripTags(); if (format == 1) current->StripTags();
else if (format == 2) current->ConvertTagsToSRT(); else if (format == 2) current->ConvertTagsToSRT();
// Replace line breaks // Replace line breaks
current->Text.Replace("\\h"," ",true); current->Text.Replace("\\h", " ");
current->Text.Replace("\\n",lineEnd,true); current->Text.Replace("\\n", lineEnd);
current->Text.Replace("\\N",lineEnd,true); current->Text.Replace("\\N", lineEnd);
if (mergeLineBreaks) { if (mergeLineBreaks) {
while (current->Text.Replace(lineEnd+lineEnd,lineEnd,true)) {}; while (current->Text.Replace(lineEnd+lineEnd, lineEnd));
} }
} }
} }
} }
/// @brief Remove all comment lines
///
void SubtitleFormat::StripComments() { void SubtitleFormat::StripComments() {
using std::list; for (std::list<AssEntry*>::iterator it = Line->begin(); it != Line->end(); ) {
list<AssEntry*>::iterator next; AssDialogue *diag = dynamic_cast<AssDialogue*>(*it);
if (!diag || (!diag->Comment && diag->Text.size()))
for (list<AssEntry*>::iterator cur = Line->begin(); cur != Line->end(); cur = next) { ++it;
next = cur; else {
next++; delete *it;
Line->erase(it++);
AssDialogue *dlg = dynamic_cast<AssDialogue*>(*cur);
if (dlg && (dlg->Comment || dlg->Text.IsEmpty())) {
delete *cur;
Line->erase(cur);
} }
} }
} }
/// @brief Remove all non-dialogue lines
///
void SubtitleFormat::StripNonDialogue() { void SubtitleFormat::StripNonDialogue() {
using std::list; for (std::list<AssEntry*>::iterator it = Line->begin(); it != Line->end(); ) {
list<AssEntry*>::iterator next; if (dynamic_cast<AssDialogue*>(*it))
++it;
for (list<AssEntry*>::iterator cur = Line->begin(); cur != Line->end(); cur = next) { else {
next = cur; delete *it;
next++; Line->erase(it++);
if (!dynamic_cast<AssDialogue*>(*cur)) {
delete *cur;
Line->erase(cur);
} }
} }
} }
/// @brief Helper function for RecombineOverlaps() static bool dialog_start_lt(AssEntry *pos, AssDialogue *to_insert) {
/// @param list AssDialogue *diag = dynamic_cast<AssDialogue*>(pos);
/// @param next return diag && diag->Start > to_insert->Start;
/// @param newdlg
///
static void InsertLineSortedIntoList(std::list<AssEntry*> &list, std::list<AssEntry*>::iterator next, AssDialogue *newdlg) {
std::list<AssEntry*>::iterator insertpos = next;
bool inserted = false;
while (insertpos != list.end()) {
AssDialogue *candidate = dynamic_cast<AssDialogue*>(*insertpos);
if (candidate && candidate->Start >= newdlg->Start) {
list.insert(insertpos, newdlg);
inserted = true;
break;
}
insertpos++;
}
if (!inserted) {
list.push_back(newdlg);
}
} }
/// @brief Split and merge lines so there are no overlapping lines /// @brief Split and merge lines so there are no overlapping lines
/// ///
/// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge /// Algorithm described at http://devel.aegisub.org/wiki/Technical/SplitMerge
void SubtitleFormat::RecombineOverlaps() { void SubtitleFormat::RecombineOverlaps() {
using std::list; std::list<AssEntry*>::iterator cur, next = Line->begin();
list<AssEntry*>::iterator next; cur = next++;
for (list<AssEntry*>::iterator cur = Line->begin(); cur != Line->end(); cur = next) { for (; next != Line->end(); cur = next++) {
next = cur;
next++;
if (next == Line->end()) break;
AssDialogue *prevdlg = dynamic_cast<AssDialogue*>(*cur); AssDialogue *prevdlg = dynamic_cast<AssDialogue*>(*cur);
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(*next); AssDialogue *curdlg = dynamic_cast<AssDialogue*>(*next);
if (curdlg && prevdlg && prevdlg->End > curdlg->Start) { if (!curdlg || !prevdlg) continue;
// Use names like in the algorithm description and prepare for erasing if (prevdlg->End <= curdlg->Start) continue;
// old dialogues from the list
list<AssEntry*>::iterator prev = cur; // Use names like in the algorithm description and prepare for erasing
cur = next; // old dialogues from the list
next++; std::list<AssEntry*>::iterator prev = cur;
cur = next;
// std::list::insert() inserts items before the given iterator, so next++;
// we need 'next' for inserting. 'prev' and 'cur' can safely be erased
// from the list now. // std::list::insert() inserts items before the given iterator, so
Line->erase(prev); // we need 'next' for inserting. 'prev' and 'cur' can safely be erased
Line->erase(cur); // from the list now.
Line->erase(prev);
//Is there an A part before the overlap? Line->erase(cur);
if (curdlg->Start > prevdlg->Start) {
// Produce new entry with correct values //Is there an A part before the overlap?
AssDialogue *newdlg = dynamic_cast<AssDialogue*>(prevdlg->Clone()); if (curdlg->Start > prevdlg->Start) {
newdlg->Start = prevdlg->Start; // Produce new entry with correct values
newdlg->End = curdlg->Start; AssDialogue *newdlg = dynamic_cast<AssDialogue*>(prevdlg->Clone());
newdlg->Text = prevdlg->Text; newdlg->Start = prevdlg->Start;
newdlg->End = curdlg->Start;
InsertLineSortedIntoList(*Line, next, newdlg); newdlg->Text = prevdlg->Text;
}
Line->insert(find_if(next, Line->end(), bind(dialog_start_lt, _1, newdlg)), newdlg);
// Overlapping A+B part
{
AssDialogue *newdlg = dynamic_cast<AssDialogue*>(prevdlg->Clone());
newdlg->Start = curdlg->Start;
newdlg->End = (prevdlg->End < curdlg->End) ? prevdlg->End : curdlg->End;
// Put an ASS format hard linewrap between lines
newdlg->Text = curdlg->Text + "\\N" + prevdlg->Text;
InsertLineSortedIntoList(*Line, next, newdlg);
}
// Is there an A part after the overlap?
if (prevdlg->End > curdlg->End) {
// Produce new entry with correct values
AssDialogue *newdlg = dynamic_cast<AssDialogue*>(prevdlg->Clone());
newdlg->Start = curdlg->End;
newdlg->End = prevdlg->End;
newdlg->Text = prevdlg->Text;
InsertLineSortedIntoList(*Line, next, newdlg);
}
// Is there a B part after the overlap?
if (curdlg->End > prevdlg->End) {
// Produce new entry with correct values
AssDialogue *newdlg = dynamic_cast<AssDialogue*>(prevdlg->Clone());
newdlg->Start = prevdlg->End;
newdlg->End = curdlg->End;
newdlg->Text = curdlg->Text;
InsertLineSortedIntoList(*Line, next, newdlg);
}
next--;
} }
// Overlapping A+B part
{
AssDialogue *newdlg = dynamic_cast<AssDialogue*>(prevdlg->Clone());
newdlg->Start = curdlg->Start;
newdlg->End = (prevdlg->End < curdlg->End) ? prevdlg->End : curdlg->End;
// 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);
}
// Is there an A part after the overlap?
if (prevdlg->End > curdlg->End) {
// Produce new entry with correct values
AssDialogue *newdlg = dynamic_cast<AssDialogue*>(prevdlg->Clone());
newdlg->Start = curdlg->End;
newdlg->End = prevdlg->End;
newdlg->Text = prevdlg->Text;
Line->insert(find_if(next, Line->end(), bind(dialog_start_lt, _1, newdlg)), newdlg);
}
// Is there a B part after the overlap?
if (curdlg->End > prevdlg->End) {
// Produce new entry with correct values
AssDialogue *newdlg = dynamic_cast<AssDialogue*>(prevdlg->Clone());
newdlg->Start = prevdlg->End;
newdlg->End = curdlg->End;
newdlg->Text = curdlg->Text;
Line->insert(find_if(next, Line->end(), bind(dialog_start_lt, _1, newdlg)), newdlg);
}
next--;
} }
} }
/// @brief Merge identical lines that follow each other /// @brief Merge identical lines that follow each other
///
void SubtitleFormat::MergeIdentical() { void SubtitleFormat::MergeIdentical() {
using std::list; std::list<AssEntry*>::iterator cur, next = Line->begin();
list<AssEntry*>::iterator next; cur = next++;
for (list<AssEntry*>::iterator cur = Line->begin(); cur != Line->end(); cur = next) { for (; next != Line->end(); cur = next++) {
next = cur;
next++;
if (next == Line->end()) break;
AssDialogue *curdlg = dynamic_cast<AssDialogue*>(*cur); AssDialogue *curdlg = dynamic_cast<AssDialogue*>(*cur);
AssDialogue *nextdlg = dynamic_cast<AssDialogue*>(*next); AssDialogue *nextdlg = dynamic_cast<AssDialogue*>(*next);
if (curdlg && nextdlg && curdlg->End == nextdlg->Start && curdlg->Text == nextdlg->Text) { if (curdlg && nextdlg && curdlg->End == nextdlg->Start && curdlg->Text == nextdlg->Text) {
// Merge timing // Merge timing
nextdlg->Start = (nextdlg->Start < curdlg->Start ? nextdlg->Start : curdlg->Start); nextdlg->Start = std::min(nextdlg->Start, curdlg->Start);
nextdlg->End = (nextdlg->End > curdlg->End ? nextdlg->End : curdlg->End); nextdlg->End = std::max(nextdlg->End, curdlg->End);
// Remove duplicate line // Remove duplicate line
delete *cur; delete *cur;
@ -556,3 +339,66 @@ void SubtitleFormat::MergeIdentical() {
} }
} }
} }
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();
#ifdef _DEBUG
new DVDSubtitleFormat();
#endif
}
}
void SubtitleFormat::DestroyFormats() {
for (std::list<SubtitleFormat*>::iterator it = formats.begin(); it != formats.end(); )
delete *it++;
}
template<class Cont, class Pred>
SubtitleFormat *find_or_null(Cont &container, Pred pred) {
typename Cont::iterator it = find_if(container.begin(), container.end(), pred);
if (it == container.end())
return 0;
return *it;
}
SubtitleFormat *SubtitleFormat::GetReader(wxString const& filename) {
LoadFormats();
return find_or_null(formats, bind(&SubtitleFormat::CanReadFile, _1, filename));
}
SubtitleFormat *SubtitleFormat::GetWriter(wxString const& filename) {
LoadFormats();
return find_or_null(formats, bind(&SubtitleFormat::CanWriteFile, _1, filename));
}
wxString SubtitleFormat::GetWildcards(int mode) {
LoadFormats();
wxArrayString all;
wxString final;
std::list<SubtitleFormat*>::iterator curIter;
for (curIter=formats.begin();curIter!=formats.end();curIter++) {
SubtitleFormat *format = *curIter;
wxArrayString cur = mode == 0 ? format->GetReadWildcards() : format->GetWriteWildcards();
if (cur.empty()) continue;
for_each(cur.begin(), cur.end(), bind(&wxString::Prepend, _1, "*."));
copy(cur.begin(), cur.end(), std::back_inserter(all));
final += "|" + format->GetName() + " (" + wxJoin(cur, ',') + ")|" + wxJoin(cur, ';');
}
final.Prepend(_("All Supported Formats") + " (" + wxJoin(all, ',') + ")|" + wxJoin(all, ';'));
return final;
}

View file

@ -54,96 +54,113 @@ class AssEntry;
/// ///
/// DOCME /// DOCME
class SubtitleFormat { class SubtitleFormat {
/// DOCME wxString name;
bool isCopy; bool isCopy;
/// DOCME
AssFile *assFile; AssFile *assFile;
void Register(); /// Get this format's wildcards for a load dialog
void Remove(); virtual wxArrayString GetReadWildcards() const { return wxArrayString(); }
/// Get this format's wildcards for a save dialog
virtual wxArrayString GetWriteWildcards() const { return wxArrayString(); }
/// DOCME /// List of loaded subtitle formats
static std::list<SubtitleFormat*> formats; static std::list<SubtitleFormat*> formats;
/// DOCME
static bool loaded;
protected: protected:
/// DOCME
struct FPSRational { struct FPSRational {
/// DOCME
int num; int num;
/// DOCME
int den; int den;
/// DOCME
bool smpte_dropframe; bool smpte_dropframe;
}; };
/// DOCME
std::list<AssEntry*> *Line; std::list<AssEntry*> *Line;
/// Copy the input subtitles file; must be called before making any changes
void CreateCopy(); void CreateCopy();
/// Delete the subtitle file if we own it; should be called after processing
/// if CreateCopy was used
void ClearCopy(); void ClearCopy();
/// Sort the lines by start time
void SortLines(); void SortLines();
void ConvertTags(int format,const wxString &lineEnd,bool mergeLineBreaks=true); /// Strip tags or convert them to SRT
//void Merge(bool identical,bool overlaps,bool stripComments,bool stripNonDialogue); /// @param format 1: strip tags 2: SRT
/// @param lineEnd Newline character(s)
/// @param mergeLineBreaks Should multiple consecutive line breaks be merged into one?
void ConvertTags(int format, const wxString &lineEnd, bool mergeLineBreaks=true);
/// Remove All commented and empty lines
void StripComments(); void StripComments();
/// Remove everything but the dialogue lines
void StripNonDialogue(); void StripNonDialogue();
/// @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();
/// Merge sequential identical lines
void MergeIdentical(); void MergeIdentical();
/// Clear the subtitle file
void Clear(); void Clear();
/// Load the default file
/// @param defline Add a blank line?
void LoadDefault(bool defline=true); void LoadDefault(bool defline=true);
/// @brief DOCME
/// @return
///
AssFile *GetAssFile() { return assFile; } AssFile *GetAssFile() { return assFile; }
/// Add a line to the output file
/// @param data Line data
/// @param group File section
void AddLine(wxString data,wxString group,int &version,wxString *outgroup=NULL); void AddLine(wxString data,wxString group,int &version,wxString *outgroup=NULL);
/// Prompt the user for a framerate to use
/// @param showSMPTE Include SMPTE as an option?
FPSRational AskForFPS(bool showSMPTE=false); FPSRational AskForFPS(bool showSMPTE=false);
virtual wxString GetName()=0;
virtual wxArrayString GetReadWildcards();
virtual wxArrayString GetWriteWildcards();
public: public:
SubtitleFormat(); /// Constructor
/// @param Subtitle format name
/// @note Automatically registers the format
SubtitleFormat(wxString const& name);
/// Destructor
/// @note Automatically unregisters the format
virtual ~SubtitleFormat(); virtual ~SubtitleFormat();
/// Set the target file to write
void SetTarget(AssFile *file); 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
/// 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
/// format's wildcard list
virtual bool CanWriteFile(wxString const& filename) const;
/// Load a subtitle file
/// @param filename File to load
/// @param forceEncoding Encoding to use or empty string for default
virtual void ReadFile(wxString const& filename, wxString const& forceEncoding="") { }
/// Save a subtitle file
/// @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="") { }
/// Get the wildcards for a save or load dialog
/// @param mode 0: load 1: save
static wxString GetWildcards(int mode); static wxString GetWildcards(int mode);
/// @brief DOCME /// Get a subtitle format that can read the given file or NULL if none can
/// @param filename static SubtitleFormat *GetReader(wxString const& filename);
/// @return /// Get a subtitle format that can write the given file or NULL if none can
/// static SubtitleFormat *GetWriter(wxString const& filename);
virtual bool CanReadFile(wxString filename) { return false; }; /// Initialize subtitle formats
/// @brief DOCME
/// @param filename
/// @return
///
virtual bool CanWriteFile(wxString filename) { return false; };
/// @brief DOCME
/// @param filename
/// @param forceEncoding
///
virtual void ReadFile(wxString filename,wxString forceEncoding="") { };
/// @brief DOCME
/// @param filename
/// @param encoding
///
virtual void WriteFile(wxString filename,wxString encoding="") { };
static SubtitleFormat *GetReader(wxString filename);
static SubtitleFormat *GetWriter(wxString filename);
static void LoadFormats(); static void LoadFormats();
/// Deinitialize subtitle formats
static void DestroyFormats(); static void DestroyFormats();
}; };

View file

@ -34,148 +34,92 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#include "ass_dialogue.h"
#include "subtitle_format_ass.h" #include "subtitle_format_ass.h"
#include "ass_dialogue.h"
#include "compat.h"
#include "text_file_reader.h" #include "text_file_reader.h"
#include "text_file_writer.h" #include "text_file_writer.h"
DEFINE_SIMPLE_EXCEPTION(AssParseError, SubtitleFormatParseError, "subtitle_io/parse/ass")
/// @brief Can read? ASSSubtitleFormat::ASSSubtitleFormat()
/// @param filename : SubtitleFormat("Advanced Substation Alpha")
/// @return {
///
bool ASSSubtitleFormat::CanReadFile(wxString filename) {
return (filename.Right(4).Lower() == ".ass" || filename.Right(4).Lower() == ".ssa");
} }
wxArrayString ASSSubtitleFormat::GetReadWildcards() const {
/// @brief Get name
/// @return
///
wxString ASSSubtitleFormat::GetName() {
return "Advanced Substation Alpha";
}
/// @brief Get read wildcards
/// @return
///
wxArrayString ASSSubtitleFormat::GetReadWildcards() {
wxArrayString formats; wxArrayString formats;
formats.Add("ass"); formats.Add("ass");
formats.Add("ssa"); formats.Add("ssa");
return formats; return formats;
} }
wxArrayString ASSSubtitleFormat::GetWriteWildcards() const {
/// @brief Get write wildcards
/// @return
///
wxArrayString ASSSubtitleFormat::GetWriteWildcards() {
wxArrayString formats; wxArrayString formats;
formats.Add("ass"); formats.Add("ass");
formats.Add("ssa"); formats.Add("ssa");
return formats; return formats;
} }
void ASSSubtitleFormat::ReadFile(wxString const& filename, wxString const& encoding) {
/// @brief Read file
/// @param filename
/// @param encoding
///
void ASSSubtitleFormat::ReadFile(wxString filename,wxString encoding) {
using namespace std; using namespace std;
// Reader TextFileReader file(filename, encoding);
TextFileReader file(filename,encoding); int version = filename.Right(4).Lower() != ".ssa";
int version = 1;
if (filename.Right(4).Lower() == ".ssa") version = 0;
// Parse file
wxString curgroup; wxString curgroup;
wxString wxbuffer;
while (file.HasMoreLines()) { while (file.HasMoreLines()) {
// Reads line wxString line = file.ReadLineFromFile();
wxbuffer = file.ReadLineFromFile();
// Make sure that the first non-blank non-comment non-group-header line // Make sure that the first non-blank non-comment non-group-header line
// is really [Script Info] // is really [Script Info]
if (curgroup.IsEmpty() && !wxbuffer.IsEmpty() && wxbuffer[0] != ';' && wxbuffer[0] != '[') { if (curgroup.empty() && !line.empty() && line[0] != ';' && line[0] != '[') {
curgroup = "[Script Info]"; curgroup = "[Script Info]";
AddLine(curgroup,curgroup,version,&curgroup); AddLine(curgroup, curgroup, version, &curgroup);
} }
// Convert v4 styles to v4+ styles // Convert v4 styles to v4+ styles
if (!wxbuffer.IsEmpty() && wxbuffer[0] == '[') { if (!line.empty() && line[0] == '[') {
// Ugly hacks to allow intermixed v4 and v4+ style sections // Ugly hacks to allow intermixed v4 and v4+ style sections
wxString low = wxbuffer.Lower(); wxString low = line.Lower();
if (low == "[v4 styles]") { if (low == "[v4 styles]") {
wxbuffer = "[V4+ Styles]"; line = "[V4+ Styles]";
curgroup = wxbuffer; curgroup = line;
version = 0; version = 0;
} }
else if (low == "[v4+ styles]") { else if (low == "[v4+ styles]") {
wxbuffer = "[V4+ Styles]"; line = "[V4+ Styles]";
curgroup = wxbuffer; curgroup = line;
version = 1; version = 1;
} }
else if (low == "[v4++ styles]") { else if (low == "[v4++ styles]") {
wxbuffer = "[V4+ Styles]"; line = "[V4+ Styles]";
curgroup = wxbuffer; curgroup = line;
version = 2; version = 2;
} }
// Not-so-special case for other groups, just set it // Not-so-special case for other groups, just set it
else { else {
curgroup = wxbuffer; curgroup = line;
} }
} }
// Add line
try { try {
AddLine(wxbuffer,curgroup,version,&curgroup); AddLine(line, curgroup, version, &curgroup);
} }
catch (const char *err) { catch (const char *err) {
Clear(); Clear();
throw wxString("Error processing line: ") + wxbuffer + ": " + wxString(err); throw AssParseError("Error processing line: " + STD_STR(line) + ": " + err, 0);
}
catch (...) {
Clear();
throw wxString("Error processing line: ") + wxbuffer;
} }
} }
} }
void ASSSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) {
TextFileWriter file(filename, encoding);
/// @brief Can write to file?
/// @param filename
/// @return
///
bool ASSSubtitleFormat::CanWriteFile(wxString filename) {
return (filename.Right(4).Lower() == ".ass" || filename.Right(4).Lower() == ".ssa");
}
/// @brief Write file
/// @param _filename
/// @param encoding
///
void ASSSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
// Open file
TextFileWriter file(filename,encoding);
bool ssa = filename.Right(4).Lower() == ".ssa"; bool ssa = filename.Right(4).Lower() == ".ssa";
// Write lines
std::list<AssEntry*>::iterator last = Line->end(); --last; std::list<AssEntry*>::iterator last = Line->end(); --last;
wxString group = Line->front()->group; wxString group = Line->front()->group;
for (std::list<AssEntry*>::iterator cur=Line->begin(); cur!=Line->end(); ++cur) { for (std::list<AssEntry*>::iterator cur=Line->begin(); cur!=Line->end(); ++cur) {
@ -189,9 +133,7 @@ void ASSSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
bool lineBreak = cur != last; bool lineBreak = cur != last;
// Write line // Write line
if (ssa) file.WriteLineToFile((*cur)->GetSSAText(),lineBreak); if (ssa) file.WriteLineToFile((*cur)->GetSSAText(), lineBreak);
else file.WriteLineToFile((*cur)->GetEntryData(),lineBreak); else file.WriteLineToFile((*cur)->GetEntryData(), lineBreak);
} }
} }

View file

@ -34,20 +34,8 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "subtitle_format.h" #include "subtitle_format.h"
//////////////
// Prototypes
class AssDialogue;
/// DOCME /// DOCME
/// @class ASSSubtitleFormat /// @class ASSSubtitleFormat
/// @brief DOCME /// @brief DOCME
@ -55,15 +43,11 @@ class AssDialogue;
/// DOCME /// DOCME
class ASSSubtitleFormat : public SubtitleFormat { class ASSSubtitleFormat : public SubtitleFormat {
public: public:
wxString GetName(); ASSSubtitleFormat();
wxArrayString GetReadWildcards();
wxArrayString GetWriteWildcards();
bool CanReadFile(wxString filename); wxArrayString GetReadWildcards() const;
void ReadFile(wxString filename,wxString forceEncoding); wxArrayString GetWriteWildcards() const;
bool CanWriteFile(wxString filename); void ReadFile(wxString const& filename, wxString const& forceEncoding);
void WriteFile(wxString filename,wxString encoding); void WriteFile(wxString const& filename, wxString const& encoding);
}; };

View file

@ -34,19 +34,16 @@
/// @ingroup subtitle_io vobsub /// @ingroup subtitle_io vobsub
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#include "subtitle_format_dvd.h"
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "subtitle_format_dvd.h"
#include "include/aegisub/subtitles_provider.h" #include "include/aegisub/subtitles_provider.h"
#include "video_provider_dummy.h" #include "video_provider_dummy.h"
/// DOCME
#undef _OPENMP #undef _OPENMP
#ifdef _OPENMP #ifdef _OPENMP
#include <omp.h> #include <omp.h>
@ -58,41 +55,17 @@
// //
//#pragma comment(lib, "tessdll.lib") //#pragma comment(lib, "tessdll.lib")
DVDSubtitleFormat::DVDSubtitleFormat()
: SubtitleFormat("DVD Subpictures")
/// @brief Format name {
/// @return
///
wxString DVDSubtitleFormat::GetName() {
return "DVD Subpictures";
} }
wxArrayString DVDSubtitleFormat::GetWriteWildcards() const {
/// @brief Extensions
/// @return
///
wxArrayString DVDSubtitleFormat::GetWriteWildcards() {
wxArrayString results; wxArrayString results;
results.Add("sup"); results.Add("sup");
return results; return results;
} }
/// @brief Can write
/// @param filename
/// @return
///
bool DVDSubtitleFormat::CanWriteFile(wxString filename) {
return (filename.Lower().EndsWith(".sup"));
}
/// @brief Get subpicture list
/// @param pics
///
void DVDSubtitleFormat::GetSubPictureList(std::vector<SubPicture> &pics) { void DVDSubtitleFormat::GetSubPictureList(std::vector<SubPicture> &pics) {
// Create video frame // Create video frame
int w = 720; int w = 720;
@ -361,7 +334,7 @@ void DVDSubtitleFormat::GetSubPictureList(std::vector<SubPicture> &pics) {
/// @param filename /// @param filename
/// @param encoding /// @param encoding
/// ///
void DVDSubtitleFormat::WriteFile(wxString filename,wxString encoding) { void DVDSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) {
// Prepare subtitles // Prepare subtitles
CreateCopy(); CreateCopy();
SortLines(); SortLines();

View file

@ -34,18 +34,12 @@
/// @ingroup subtitle_io vobsub /// @ingroup subtitle_io vobsub
/// ///
///////////
// Headers
#ifndef AGI_PRE #ifndef AGI_PRE
#include <vector> #include <vector>
#endif #endif
#include "subtitle_format.h" #include "subtitle_format.h"
/// DOCME /// DOCME
struct SubPicture { struct SubPicture {
@ -55,17 +49,17 @@ struct SubPicture {
/// DOCME /// DOCME
/// DOCME /// DOCME
int x,y; int x, y;
/// DOCME /// DOCME
/// DOCME /// DOCME
int w,h; int w, h;
/// DOCME /// DOCME
/// DOCME /// DOCME
int start,end; int start, end;
}; };
@ -81,12 +75,7 @@ struct RLEGroup {
/// DOCME /// DOCME
bool eol; bool eol;
/// @brief DOCME RLEGroup(int col, int len, bool eol) : col(col), len(len), eol(eol) { }
/// @param _col
/// @param _len
/// @param _eol
///
RLEGroup(int _col,int _len,bool _eol) { col = _col; len = _len; eol = _eol; }
}; };
@ -97,14 +86,10 @@ struct RLEGroup {
/// ///
/// DOCME /// DOCME
class DVDSubtitleFormat : public SubtitleFormat { class DVDSubtitleFormat : public SubtitleFormat {
private:
void GetSubPictureList(std::vector<SubPicture> &pics); void GetSubPictureList(std::vector<SubPicture> &pics);
public: public:
wxString GetName(); DVDSubtitleFormat();
wxArrayString GetWriteWildcards(); wxArrayString GetWriteWildcards() const;
bool CanWriteFile(wxString filename); void WriteFile(wxString const& filename, wxString const& encoding);
void WriteFile(wxString filename,wxString encoding);
}; };

View file

@ -34,57 +34,29 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#include "ass_dialogue.h"
#include "subtitle_format_encore.h" #include "subtitle_format_encore.h"
#include "ass_dialogue.h"
#include "text_file_writer.h" #include "text_file_writer.h"
EncoreSubtitleFormat::EncoreSubtitleFormat()
/// @brief Name : SubtitleFormat("Adobe Encore")
/// @return {
///
wxString EncoreSubtitleFormat::GetName() {
return "Adobe Encore";
} }
wxArrayString EncoreSubtitleFormat::GetWriteWildcards() const {
/// @brief Wildcards
/// @return
///
wxArrayString EncoreSubtitleFormat::GetWriteWildcards() {
wxArrayString formats; wxArrayString formats;
formats.Add("encore.txt"); formats.Add("encore.txt");
return formats; return formats;
} }
void EncoreSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) {
/// @brief Can write file?
/// @param filename
/// @return
///
bool EncoreSubtitleFormat::CanWriteFile(wxString filename) {
return (filename.Right(11).Lower() == ".encore.txt");
}
/// @brief Write file
/// @param _filename
/// @param encoding
///
void EncoreSubtitleFormat::WriteFile(wxString _filename,wxString encoding) {
// Get FPS
FPSRational fps_rat = AskForFPS(true); FPSRational fps_rat = AskForFPS(true);
if (fps_rat.num <= 0 || fps_rat.den <= 0) return; if (fps_rat.num <= 0 || fps_rat.den <= 0) return;
// Open file TextFileWriter file(filename, encoding);
TextFileWriter file(_filename,encoding);
// Convert to encore // Convert to encore
CreateCopy(); CreateCopy();
@ -92,25 +64,20 @@ void EncoreSubtitleFormat::WriteFile(wxString _filename,wxString encoding) {
StripComments(); StripComments();
RecombineOverlaps(); RecombineOverlaps();
MergeIdentical(); MergeIdentical();
ConvertTags(1,"\r\n"); ConvertTags(1, "\r\n");
// Write lines // Write lines
using std::list;
int i = 0; int i = 0;
// Encore wants ; instead of : if we're dealing with NTSC dropframe stuff // Encore wants ; instead of : if we're dealing with NTSC dropframe stuff
FractionalTime ft(fps_rat.smpte_dropframe ? ";" : ":", fps_rat.num, fps_rat.den, fps_rat.smpte_dropframe); FractionalTime ft(fps_rat.smpte_dropframe ? ";" : ":", fps_rat.num, fps_rat.den, fps_rat.smpte_dropframe);
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) { for (std::list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
AssDialogue *current = dynamic_cast<AssDialogue*>(*cur); if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) {
if (current && !current->Comment) {
++i; ++i;
file.WriteLineToFile(wxString::Format("%i %s %s %s", i, ft.FromAssTime(current->Start), ft.FromAssTime(current->End), current->Text)); file.WriteLineToFile(wxString::Format("%i %s %s %s", i, ft.FromAssTime(current->Start), ft.FromAssTime(current->End), current->Text));
} }
} }
// Clean up
ClearCopy(); ClearCopy();
} }

View file

@ -34,11 +34,6 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "subtitle_format.h" #include "subtitle_format.h"
@ -49,10 +44,7 @@
/// DOCME /// DOCME
class EncoreSubtitleFormat : public SubtitleFormat { class EncoreSubtitleFormat : public SubtitleFormat {
public: public:
wxString GetName(); EncoreSubtitleFormat();
wxArrayString GetWriteWildcards(); wxArrayString GetWriteWildcards() const;
bool CanWriteFile(wxString filename); void WriteFile(wxString const& filename, wxString const& encoding);
void WriteFile(wxString filename,wxString encoding);
}; };

View file

@ -47,41 +47,38 @@
#include "text_file_writer.h" #include "text_file_writer.h"
#include "video_context.h" #include "video_context.h"
wxString MicroDVDSubtitleFormat::GetName() { MicroDVDSubtitleFormat::MicroDVDSubtitleFormat()
return "MicroDVD"; : SubtitleFormat("MicroDVD")
{
} }
wxArrayString MicroDVDSubtitleFormat::GetReadWildcards() { wxArrayString MicroDVDSubtitleFormat::GetReadWildcards() const {
wxArrayString formats; wxArrayString formats;
formats.Add("sub"); formats.Add("sub");
return formats; return formats;
} }
wxArrayString MicroDVDSubtitleFormat::GetWriteWildcards() { wxArrayString MicroDVDSubtitleFormat::GetWriteWildcards() const {
return GetReadWildcards(); return GetReadWildcards();
} }
bool MicroDVDSubtitleFormat::CanReadFile(wxString filename) { bool MicroDVDSubtitleFormat::CanReadFile(wxString const& filename) const {
// Return false immediately if extension is wrong // Return false immediately if extension is wrong
if (filename.Right(4).Lower() != ".sub") return false; if (filename.Right(4).Lower() != ".sub") return false;
// Since there is an infinity of .sub formats, load first line and check if it's valid // Since there is an infinity of .sub formats, load first line and check if it's valid
TextFileReader file(filename); TextFileReader file(filename);
if (file.HasMoreLines()) { if (file.HasMoreLines()) {
wxRegEx exp("^[\\{\\[]([0-9]+)[\\}\\]][\\{\\[]([0-9]+)[\\}\\]](.*)$",wxRE_ADVANCED); wxRegEx exp("^[\\{\\[]([0-9]+)[\\}\\]][\\{\\[]([0-9]+)[\\}\\]](.*)$", wxRE_ADVANCED);
return exp.Matches(file.ReadLineFromFile()); return exp.Matches(file.ReadLineFromFile());
} }
return false; return false;
} }
bool MicroDVDSubtitleFormat::CanWriteFile(wxString filename) { void MicroDVDSubtitleFormat::ReadFile(wxString const& filename, wxString const& forceEncoding) {
return (filename.Right(4).Lower() == ".sub");
}
void MicroDVDSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding) {
TextFileReader file(filename); TextFileReader file(filename);
wxRegEx exp("^[\\{\\[]([0-9]+)[\\}\\]][\\{\\[]([0-9]+)[\\}\\]](.*)$",wxRE_ADVANCED); wxRegEx exp("^[\\{\\[]([0-9]+)[\\}\\]][\\{\\[]([0-9]+)[\\}\\]](.*)$", wxRE_ADVANCED);
LoadDefault(false); LoadDefault(false);
@ -94,10 +91,10 @@ void MicroDVDSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding)
while (file.HasMoreLines()) { while (file.HasMoreLines()) {
wxString line = file.ReadLineFromFile(); wxString line = file.ReadLineFromFile();
if (exp.Matches(line)) { if (exp.Matches(line)) {
long f1,f2; long f1, f2;
exp.GetMatch(line,1).ToLong(&f1); exp.GetMatch(line, 1).ToLong(&f1);
exp.GetMatch(line,2).ToLong(&f2); exp.GetMatch(line, 2).ToLong(&f2);
wxString text = exp.GetMatch(line,3); wxString text = exp.GetMatch(line, 3);
// If it's the first, check if it contains fps information // If it's the first, check if it contains fps information
if (isFirst) { if (isFirst) {
@ -123,25 +120,20 @@ void MicroDVDSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding)
} }
} }
// Start and end times text.Replace("|", "\\N");
int start,end;
start = rate->TimeAtFrame(f1,agi::vfr::START);
end = rate->TimeAtFrame(f2,agi::vfr::END);
text.Replace("|","\\N"); AssDialogue *line = new AssDialogue;
AssDialogue *line = new AssDialogue();
line->group = "[Events]"; line->group = "[Events]";
line->Style = "Default"; line->Style = "Default";
line->Start.SetMS(start); line->Start.SetMS(rate->TimeAtFrame(f1, agi::vfr::START));
line->End.SetMS(end); line->End.SetMS(rate->TimeAtFrame(f2, agi::vfr::END));
line->Text = text; line->Text = text;
Line->push_back(line); Line->push_back(line);
} }
} }
} }
void MicroDVDSubtitleFormat::WriteFile(wxString filename,wxString encoding) { void MicroDVDSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) {
agi::vfr::Framerate cfr; agi::vfr::Framerate cfr;
const agi::vfr::Framerate *rate = &cfr; const agi::vfr::Framerate *rate = &cfr;
@ -157,24 +149,22 @@ void MicroDVDSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
StripComments(); StripComments();
RecombineOverlaps(); RecombineOverlaps();
MergeIdentical(); MergeIdentical();
ConvertTags(1,"|"); ConvertTags(1, "|");
TextFileWriter file(filename,encoding); TextFileWriter file(filename, encoding);
// Write FPS line // Write FPS line
if (!rate->IsVFR()) { if (!rate->IsVFR()) {
file.WriteLineToFile(wxString::Format("{1}{1}%.6f",rate->FPS())); file.WriteLineToFile(wxString::Format("{1}{1}%.6f", rate->FPS()));
} }
// Write lines // Write lines
using std::list; for (std::list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) { if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) {
AssDialogue *current = dynamic_cast<AssDialogue*>(*cur); int start = rate->FrameAtTime(current->Start.GetMS(), agi::vfr::START);
if (current && !current->Comment) { int end = rate->FrameAtTime(current->End.GetMS(), agi::vfr::END);
int start = rate->FrameAtTime(current->Start.GetMS(),agi::vfr::START);
int end = rate->FrameAtTime(current->End.GetMS(),agi::vfr::END);
file.WriteLineToFile(wxString::Format("{%i}{%i}%s",start,end,current->Text)); file.WriteLineToFile(wxString::Format("{%i}{%i}%s", start, end, current->Text));
} }
} }

View file

@ -43,13 +43,13 @@
/// DOCME /// DOCME
class MicroDVDSubtitleFormat : public SubtitleFormat { class MicroDVDSubtitleFormat : public SubtitleFormat {
public: public:
wxString GetName(); MicroDVDSubtitleFormat();
wxArrayString GetReadWildcards();
wxArrayString GetWriteWildcards();
bool CanReadFile(wxString filename); wxArrayString GetReadWildcards() const;
void ReadFile(wxString filename,wxString forceEncoding); wxArrayString GetWriteWildcards() const;
bool CanWriteFile(wxString filename); bool CanReadFile(wxString const& filename) const;
void WriteFile(wxString filename,wxString encoding); void ReadFile(wxString const& filename, wxString const& forceEncoding);
void WriteFile(wxString const& filename, wxString const& encoding);
}; };

View file

@ -34,44 +34,18 @@
/// @ingroup subtitle_io matroska /// @ingroup subtitle_io matroska
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#include "ass_dialogue.h"
#include "ass_file.h"
#include "mkv_wrap.h"
#include "subtitle_format_mkv.h" #include "subtitle_format_mkv.h"
#include "mkv_wrap.h"
/// @brief Can read? MKVSubtitleFormat::MKVSubtitleFormat()
/// @param filename : SubtitleFormat("Matroska")
/// @return {
///
bool MKVSubtitleFormat::CanReadFile(wxString filename) {
if (filename.Right(4).Lower() == ".mkv" || filename.Right(4).Lower() == ".mks"
|| filename.Right(4).Lower() == ".mka")
return true;
else
return false;
} }
wxArrayString MKVSubtitleFormat::GetReadWildcards() const {
/// @brief Get name
/// @return
///
wxString MKVSubtitleFormat::GetName() {
return "Matroska";
}
/// @brief Get read wildcards
/// @return
///
wxArrayString MKVSubtitleFormat::GetReadWildcards() {
wxArrayString formats; wxArrayString formats;
formats.Add("mkv"); formats.Add("mkv");
formats.Add("mka"); formats.Add("mka");
@ -79,41 +53,8 @@ wxArrayString MKVSubtitleFormat::GetReadWildcards() {
return formats; return formats;
} }
void MKVSubtitleFormat::ReadFile(wxString const& filename, wxString const& encoding) {
/// @brief Read file
/// @param filename
/// @param encoding
///
void MKVSubtitleFormat::ReadFile(wxString filename,wxString encoding) {
// Open matroska
MatroskaWrapper wrap; MatroskaWrapper wrap;
wrap.Open(filename,false); wrap.Open(filename, false);
// Read subtitles in a temporary object
wrap.GetSubtitles(GetAssFile()); wrap.GetSubtitles(GetAssFile());
// Close matroska
wrap.Close();
} }
/// @brief Can write to file?
/// @param filename
/// @return
///
bool MKVSubtitleFormat::CanWriteFile(wxString filename) {
return false;
}
/// @brief Write file
/// @param _filename
/// @param encoding
///
void MKVSubtitleFormat::WriteFile(wxString _filename,wxString encoding) {
}

View file

@ -34,19 +34,8 @@
/// @ingroup subtitle_io matroska /// @ingroup subtitle_io matroska
/// ///
///////////
// Headers
#include "subtitle_format.h" #include "subtitle_format.h"
//////////////
// Prototypes
class AssDialogue;
/// DOCME /// DOCME
/// @class MKVSubtitleFormat /// @class MKVSubtitleFormat
/// @brief DOCME /// @brief DOCME
@ -54,14 +43,8 @@ class AssDialogue;
/// DOCME /// DOCME
class MKVSubtitleFormat : public SubtitleFormat { class MKVSubtitleFormat : public SubtitleFormat {
public: public:
wxString GetName(); MKVSubtitleFormat();
wxArrayString GetReadWildcards(); wxArrayString GetReadWildcards() const;
bool CanReadFile(wxString filename); void ReadFile(wxString const& filename, wxString const& forceEncoding);
void ReadFile(wxString filename,wxString forceEncoding);
bool CanWriteFile(wxString filename);
void WriteFile(wxString filename,wxString encoding);
}; };

View file

@ -34,9 +34,6 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#ifndef AGI_PRE #ifndef AGI_PRE
@ -52,67 +49,26 @@
DEFINE_SIMPLE_EXCEPTION(SRTParseError, SubtitleFormatParseError, "subtitle_io/parse/srt") DEFINE_SIMPLE_EXCEPTION(SRTParseError, SubtitleFormatParseError, "subtitle_io/parse/srt")
SRTSubtitleFormat::SRTSubtitleFormat()
/// @brief Can read? : SubtitleFormat("SubRip")
/// @param filename {
/// @return
///
bool SRTSubtitleFormat::CanReadFile(wxString filename) {
return (filename.Right(4).Lower() == ".srt");
} }
wxArrayString SRTSubtitleFormat::GetReadWildcards() const {
/// @brief Can write?
/// @param filename
/// @return
///
bool SRTSubtitleFormat::CanWriteFile(wxString filename) {
return (filename.Right(4).Lower() == ".srt");
}
/// @brief Get name
/// @return
///
wxString SRTSubtitleFormat::GetName() {
return "SubRip";
}
/// @brief Get read wildcards
/// @return
///
wxArrayString SRTSubtitleFormat::GetReadWildcards() {
wxArrayString formats; wxArrayString formats;
formats.Add("srt"); formats.Add("srt");
return formats; return formats;
} }
wxArrayString SRTSubtitleFormat::GetWriteWildcards() const {
/// @brief Get write wildcards
/// @return
///
wxArrayString SRTSubtitleFormat::GetWriteWildcards() {
return GetReadWildcards(); return GetReadWildcards();
} }
void SRTSubtitleFormat::ReadFile(wxString const& filename, wxString const& encoding) {
/// @brief Read file
/// @param filename
/// @param encoding
///
void SRTSubtitleFormat::ReadFile(wxString filename,wxString encoding) {
using namespace std; using namespace std;
// Reader
TextFileReader file(filename,encoding); TextFileReader file(filename,encoding);
// Default
LoadDefault(false); LoadDefault(false);
// See parsing algorithm at <http://devel.aegisub.org/wiki/SubtitleFormats/SRT> // See parsing algorithm at <http://devel.aegisub.org/wiki/SubtitleFormats/SRT>
@ -239,7 +195,7 @@ found_timestamps:
} }
if (state == 1 || state == 2) { if (state == 1 || state == 2) {
throw SRTParseError(std::string("Parsing SRT: Incomplete file"), 0); throw SRTParseError("Parsing SRT: Incomplete file", 0);
} }
if (line) { if (line) {
@ -248,15 +204,8 @@ found_timestamps:
} }
} }
void SRTSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) {
TextFileWriter file(filename,encoding);
/// @brief Write file
/// @param _filename
/// @param encoding
///
void SRTSubtitleFormat::WriteFile(wxString _filename,wxString encoding) {
// Open file
TextFileWriter file(_filename,encoding);
// Convert to SRT // Convert to SRT
CreateCopy(); CreateCopy();
@ -274,22 +223,14 @@ void SRTSubtitleFormat::WriteFile(wxString _filename,wxString encoding) {
// Write lines // Write lines
int i=1; int i=1;
using std::list; for (std::list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) { if (AssDialogue *current = dynamic_cast<AssDialogue*>(*cur)) {
AssDialogue *current = dynamic_cast<AssDialogue*>(*cur); file.WriteLineToFile(wxString::Format("%i", i++));
if (current && !current->Comment) {
// Write line
file.WriteLineToFile(wxString::Format("%i",i));
file.WriteLineToFile(current->Start.GetSRTFormated() + " --> " + current->End.GetSRTFormated()); file.WriteLineToFile(current->Start.GetSRTFormated() + " --> " + current->End.GetSRTFormated());
file.WriteLineToFile(current->Text); file.WriteLineToFile(current->Text);
file.WriteLineToFile(""); file.WriteLineToFile("");
i++;
} }
} }
// Clean up
ClearCopy(); ClearCopy();
} }

View file

@ -34,20 +34,8 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "subtitle_format.h" #include "subtitle_format.h"
//////////////
// Prototypes
class AssDialogue;
/// DOCME /// DOCME
/// @class SRTSubtitleFormat /// @class SRTSubtitleFormat
/// @brief DOCME /// @brief DOCME
@ -55,15 +43,10 @@ class AssDialogue;
/// DOCME /// DOCME
class SRTSubtitleFormat : public SubtitleFormat { class SRTSubtitleFormat : public SubtitleFormat {
public: public:
wxString GetName(); SRTSubtitleFormat();
wxArrayString GetReadWildcards(); wxArrayString GetReadWildcards() const;
wxArrayString GetWriteWildcards(); wxArrayString GetWriteWildcards() const;
bool CanReadFile(wxString filename); void ReadFile(wxString const& filename, wxString const& forceEncoding);
void ReadFile(wxString filename,wxString forceEncoding); void WriteFile(wxString const& filename, wxString const& encoding);
bool CanWriteFile(wxString filename);
void WriteFile(wxString filename,wxString encoding);
}; };

View file

@ -34,65 +34,36 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#ifndef AGI_PRE #ifndef AGI_PRE
#include <stdio.h> #include <stdio.h>
#endif #endif
#include "subtitle_format_transtation.h"
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "ass_style.h" #include "ass_style.h"
#include "ass_time.h" #include "ass_time.h"
#include "subtitle_format_transtation.h"
#include "text_file_writer.h" #include "text_file_writer.h"
TranStationSubtitleFormat::TranStationSubtitleFormat()
/// @brief Name : SubtitleFormat("TranStation")
/// @return {
///
wxString TranStationSubtitleFormat::GetName() {
return "TranStation";
} }
wxArrayString TranStationSubtitleFormat::GetWriteWildcards() const {
/// @brief Wildcards
/// @return
///
wxArrayString TranStationSubtitleFormat::GetWriteWildcards() {
wxArrayString formats; wxArrayString formats;
formats.Add("transtation.txt"); formats.Add("transtation.txt");
return formats; return formats;
} }
void TranStationSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) {
/// @brief Can write file?
/// @param filename
/// @return
///
bool TranStationSubtitleFormat::CanWriteFile(wxString filename) {
return (filename.Right(16).Lower() == ".transtation.txt");
}
/// @brief Write file
/// @param _filename
/// @param encoding
/// @return
///
void TranStationSubtitleFormat::WriteFile(wxString _filename,wxString encoding) {
// Get FPS
FPSRational fps_rat = AskForFPS(true); FPSRational fps_rat = AskForFPS(true);
if (fps_rat.num <= 0 || fps_rat.den <= 0) return; if (fps_rat.num <= 0 || fps_rat.den <= 0) return;
// Open file TextFileWriter file(filename, encoding);
TextFileWriter file(_filename,encoding);
// Convert to TranStation // Convert to TranStation
CreateCopy(); CreateCopy();
@ -101,45 +72,34 @@ void TranStationSubtitleFormat::WriteFile(wxString _filename,wxString encoding)
RecombineOverlaps(); RecombineOverlaps();
MergeIdentical(); MergeIdentical();
// Write lines AssDialogue *prev = 0;
using std::list; for (std::list<AssEntry*>::iterator it = Line->begin(); it != Line->end(); ++it) {
AssDialogue *current = NULL; AssDialogue *cur = dynamic_cast<AssDialogue*>(*it);
AssDialogue *next = NULL;
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
if (next)
current = next;
next = dynamic_cast<AssDialogue*>(*cur);
if (current && !current->Comment) { if (prev && cur) {
// Write text file.WriteLineToFile(ConvertLine(prev, &fps_rat, cur->Start.GetMS()));
file.WriteLineToFile(ConvertLine(current,&fps_rat,(next && !next->Comment) ? next->Start.GetMS() : -1));
file.WriteLineToFile(""); file.WriteLineToFile("");
} }
if (cur)
prev = cur;
} }
// flush last line // flush last line
if (next && !next->Comment) if (prev)
file.WriteLineToFile(ConvertLine(next,&fps_rat,-1)); file.WriteLineToFile(ConvertLine(prev, &fps_rat, -1));
// Every file must end with this line // Every file must end with this line
file.WriteLineToFile("SUB["); file.WriteLineToFile("SUB[");
// Clean up
ClearCopy(); ClearCopy();
} }
/// @brief DOCME
/// @param current
/// @param fps_rat
/// @param nextl_start
///
wxString TranStationSubtitleFormat::ConvertLine(AssDialogue *current, FPSRational *fps_rat, int nextl_start) { wxString TranStationSubtitleFormat::ConvertLine(AssDialogue *current, FPSRational *fps_rat, int nextl_start) {
// Get line data
AssStyle *style = GetAssFile()->GetStyle(current->Style);
int valign = 0; int valign = 0;
const char *halign = " "; // default is centered const char *halign = " "; // default is centered
const char *type = "N"; // no special style const char *type = "N"; // no special style
if (style) { if (AssStyle *style = GetAssFile()->GetStyle(current->Style)) {
if (style->alignment >= 4) valign = 4; if (style->alignment >= 4) valign = 4;
if (style->alignment >= 7) valign = 9; if (style->alignment >= 7) valign = 9;
if (style->alignment == 1 || style->alignment == 4 || style->alignment == 7) halign = "L"; if (style->alignment == 1 || style->alignment == 4 || style->alignment == 7) halign = "L";
@ -162,16 +122,15 @@ wxString TranStationSubtitleFormat::ConvertLine(AssDialogue *current, FPSRationa
end.SetMS(end.GetMS() - ((1000*fps_rat->den)/fps_rat->num)); end.SetMS(end.GetMS() - ((1000*fps_rat->den)/fps_rat->num));
FractionalTime ft(":", fps_rat->num, fps_rat->den, fps_rat->smpte_dropframe); FractionalTime ft(":", fps_rat->num, fps_rat->den, fps_rat->smpte_dropframe);
wxString header = wxString::Format("SUB[%i%s%s ",valign,halign,type) + ft.FromAssTime(start) + ">" + ft.FromAssTime(end) + "]\r\n"; wxString header = wxString::Format("SUB[%i%s%s ", valign, halign, type) + ft.FromAssTime(start) + ">" + ft.FromAssTime(end) + "]\r\n";
// Process text // Process text
wxString lineEnd = "\r\n"; wxString lineEnd = "\r\n";
current->StripTags(); current->StripTags();
current->Text.Replace("\\h"," ",true); current->Text.Replace("\\h", " ", true);
current->Text.Replace("\\n",lineEnd,true); current->Text.Replace("\\n", lineEnd, true);
current->Text.Replace("\\N",lineEnd,true); current->Text.Replace("\\N", lineEnd, true);
while (current->Text.Replace(lineEnd+lineEnd,lineEnd,true)) {}; while (current->Text.Replace(lineEnd + lineEnd, lineEnd, true));
return header + current->Text; return header + current->Text;
} }

View file

@ -34,13 +34,9 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "subtitle_format.h" #include "subtitle_format.h"
class AssDialogue;
/// DOCME /// DOCME
/// @class TranStationSubtitleFormat /// @class TranStationSubtitleFormat
@ -48,14 +44,10 @@
/// ///
/// DOCME /// DOCME
class TranStationSubtitleFormat : public SubtitleFormat { class TranStationSubtitleFormat : public SubtitleFormat {
private:
wxString ConvertLine(AssDialogue *line, FPSRational *fps_rat, int nextl_start); wxString ConvertLine(AssDialogue *line, FPSRational *fps_rat, int nextl_start);
public: public:
wxString GetName(); TranStationSubtitleFormat();
wxArrayString GetWriteWildcards(); wxArrayString GetWriteWildcards() const;
bool CanWriteFile(wxString filename); void WriteFile(wxString const& filename, wxString const& encoding);
void WriteFile(wxString filename,wxString encoding);
}; };

View file

@ -34,90 +34,49 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#include "subtitle_format_ttxt.h"
#include "ass_dialogue.h"
#include "ass_file.h" #include "ass_file.h"
#include "ass_time.h" #include "ass_time.h"
#include "compat.h" #include "compat.h"
#include "main.h" #include "main.h"
#include "subtitle_format_ttxt.h"
DEFINE_SIMPLE_EXCEPTION(TTXTParseError, SubtitleFormatParseError, "subtitle_io/parse/ttxt")
/// @brief Get format name TTXTSubtitleFormat::TTXTSubtitleFormat()
/// @return : SubtitleFormat("MPEG-4 Streaming Text")
/// {
wxString TTXTSubtitleFormat::GetName() {
return "MPEG-4 Streaming Text";
} }
wxArrayString TTXTSubtitleFormat::GetReadWildcards() const {
/// @brief Get read wildcards
/// @return
///
wxArrayString TTXTSubtitleFormat::GetReadWildcards() {
wxArrayString formats; wxArrayString formats;
formats.Add("ttxt"); formats.Add("ttxt");
return formats; return formats;
} }
wxArrayString TTXTSubtitleFormat::GetWriteWildcards() const {
/// @brief Get write wildcards
/// @return
///
wxArrayString TTXTSubtitleFormat::GetWriteWildcards() {
return GetReadWildcards(); return GetReadWildcards();
//return wxArrayString();
} }
void TTXTSubtitleFormat::ReadFile(wxString const& filename, wxString const& forceEncoding) {
/// @brief Can read a file?
/// @param filename
/// @return
///
bool TTXTSubtitleFormat::CanReadFile(wxString filename) {
return (filename.Right(5).Lower() == ".ttxt");
}
/// @brief Can write a file?
/// @param filename
/// @return
///
bool TTXTSubtitleFormat::CanWriteFile(wxString filename) {
//return false;
return (filename.Right(5).Lower() == ".ttxt");
}
/// @brief Read a file
/// @param filename
/// @param forceEncoding
///
void TTXTSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding) {
// Load default
LoadDefault(false); LoadDefault(false);
// Load XML document // Load XML document
wxXmlDocument doc; wxXmlDocument doc;
if (!doc.Load(filename)) throw "Failed loading TTXT XML file."; if (!doc.Load(filename)) throw TTXTParseError("Failed loading TTXT XML file.", 0);
// Check root node name // Check root node name
if (doc.GetRoot()->GetName() != "TextStream") throw "Invalid TTXT file."; if (doc.GetRoot()->GetName() != "TextStream") throw TTXTParseError("Invalid TTXT file.", 0);
// Check version // Check version
wxString verStr = doc.GetRoot()->GetAttribute("version",""); wxString verStr = doc.GetRoot()->GetAttribute("version", "");
version = -1; version = -1;
if (verStr == "1.0") version = 0; if (verStr == "1.0") version = 0;
else if (verStr == "1.1") version = 1; else if (verStr == "1.1") version = 1;
else throw wxString("Unknown TTXT version: " + verStr); else throw TTXTParseError("Unknown TTXT version: " + STD_STR(verStr), 0);
// Get children // Get children
diag = NULL; diag = NULL;
@ -149,15 +108,9 @@ void TTXTSubtitleFormat::ReadFile(wxString filename,wxString forceEncoding) {
} }
} }
/// @brief Process a dialogue line
/// @param node
/// @return
///
bool TTXTSubtitleFormat::ProcessLine(wxXmlNode *node) { bool TTXTSubtitleFormat::ProcessLine(wxXmlNode *node) {
// Get time // Get time
wxString sampleTime = node->GetAttribute("sampleTime","00:00:00.000"); wxString sampleTime = node->GetAttribute("sampleTime", "00:00:00.000");
AssTime time; AssTime time;
time.ParseASS(sampleTime); time.ParseASS(sampleTime);
@ -167,7 +120,7 @@ bool TTXTSubtitleFormat::ProcessLine(wxXmlNode *node) {
// Get text // Get text
wxString text; wxString text;
if (version == 0) text = node->GetAttribute("text",""); if (version == 0) text = node->GetAttribute("text", "");
else text = node->GetNodeContent(); else text = node->GetNodeContent();
// Create line // Create line
@ -199,8 +152,8 @@ bool TTXTSubtitleFormat::ProcessLine(wxXmlNode *node) {
// Process text for 1.1 // Process text for 1.1
else { else {
text.Replace("\r",""); text.Replace("\r", "");
text.Replace("\n","\\N"); text.Replace("\n", "\\N");
diag->Text = text; diag->Text = text;
} }
@ -212,30 +165,19 @@ bool TTXTSubtitleFormat::ProcessLine(wxXmlNode *node) {
else return false; else return false;
} }
/// @brief Process the header
/// @param node
///
void TTXTSubtitleFormat::ProcessHeader(wxXmlNode *node) { void TTXTSubtitleFormat::ProcessHeader(wxXmlNode *node) {
// TODO // TODO
} }
void TTXTSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) {
/// @brief Write a file
/// @param filename
/// @param encoding
///
void TTXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
// Convert to TTXT // Convert to TTXT
CreateCopy(); CreateCopy();
ConvertToTTXT(); ConvertToTTXT();
// Create XML structure // Create XML structure
wxXmlDocument doc; wxXmlDocument doc;
wxXmlNode *root = new wxXmlNode(NULL,wxXML_ELEMENT_NODE,"TextStream"); wxXmlNode *root = new wxXmlNode(NULL, wxXML_ELEMENT_NODE, "TextStream");
root->AddAttribute("version","1.1"); root->AddAttribute("version", "1.1");
doc.SetRoot(root); doc.SetRoot(root);
// Create header // Create header
@ -248,10 +190,11 @@ void TTXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) { for (list<AssEntry*>::iterator cur=Line->begin();cur!=Line->end();cur++) {
AssDialogue *current = dynamic_cast<AssDialogue*>(*cur); AssDialogue *current = dynamic_cast<AssDialogue*>(*cur);
if (current && !current->Comment) { if (current && !current->Comment) {
WriteLine(root,current); WriteLine(root, current);
i++; i++;
} }
else throw "Unexpected line type in TTXT file"; else
throw TTXTParseError("Unexpected line type in TTXT file", 0);
} }
// Save XML // Save XML
@ -262,82 +205,71 @@ void TTXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) {
ClearCopy(); ClearCopy();
} }
/// @brief Write header
/// @param root
///
void TTXTSubtitleFormat::WriteHeader(wxXmlNode *root) { void TTXTSubtitleFormat::WriteHeader(wxXmlNode *root) {
// Write stream header // Write stream header
wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE,"TextStreamHeader"); wxXmlNode *node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextStreamHeader");
node->AddAttribute("width","400"); node->AddAttribute("width", "400");
node->AddAttribute("height","60"); node->AddAttribute("height", "60");
node->AddAttribute("layer","0"); node->AddAttribute("layer", "0");
node->AddAttribute("translation_x","0"); node->AddAttribute("translation_x", "0");
node->AddAttribute("translation_y","0"); node->AddAttribute("translation_y", "0");
root->AddChild(node); root->AddChild(node);
root = node; root = node;
// Write sample description // Write sample description
node = new wxXmlNode(wxXML_ELEMENT_NODE,"TextSampleDescription"); node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextSampleDescription");
node->AddAttribute("horizontalJustification","center"); node->AddAttribute("horizontalJustification", "center");
node->AddAttribute("verticalJustification","bottom"); node->AddAttribute("verticalJustification", "bottom");
node->AddAttribute("backColor","0 0 0 0"); node->AddAttribute("backColor", "0 0 0 0");
node->AddAttribute("verticalText","no"); node->AddAttribute("verticalText", "no");
node->AddAttribute("fillTextRegion","no"); node->AddAttribute("fillTextRegion", "no");
node->AddAttribute("continuousKaraoke","no"); node->AddAttribute("continuousKaraoke", "no");
node->AddAttribute("scroll","None"); node->AddAttribute("scroll", "None");
root->AddChild(node); root->AddChild(node);
root = node; root = node;
// Write font table // Write font table
node = new wxXmlNode(wxXML_ELEMENT_NODE,"FontTable"); node = new wxXmlNode(wxXML_ELEMENT_NODE, "FontTable");
wxXmlNode *subNode = new wxXmlNode(wxXML_ELEMENT_NODE,"FontTableEntry"); wxXmlNode *subNode = new wxXmlNode(wxXML_ELEMENT_NODE, "FontTableEntry");
subNode->AddAttribute("fontName","Sans"); subNode->AddAttribute("fontName", "Sans");
subNode->AddAttribute("fontID","1"); subNode->AddAttribute("fontID", "1");
node->AddChild(subNode); node->AddChild(subNode);
root->AddChild(node); root->AddChild(node);
// Write text box // Write text box
node = new wxXmlNode(wxXML_ELEMENT_NODE,"TextBox"); node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextBox");
node->AddAttribute("top","0"); node->AddAttribute("top", "0");
node->AddAttribute("left","0"); node->AddAttribute("left", "0");
node->AddAttribute("bottom","60"); node->AddAttribute("bottom", "60");
node->AddAttribute("right","400"); node->AddAttribute("right", "400");
root->AddChild(node); root->AddChild(node);
// Write style // Write style
node = new wxXmlNode(wxXML_ELEMENT_NODE,"Style"); node = new wxXmlNode(wxXML_ELEMENT_NODE, "Style");
node->AddAttribute("styles","Normal"); node->AddAttribute("styles", "Normal");
node->AddAttribute("fontID","1"); node->AddAttribute("fontID", "1");
node->AddAttribute("fontSize","18"); node->AddAttribute("fontSize", "18");
node->AddAttribute("color","ff ff ff ff"); node->AddAttribute("color", "ff ff ff ff");
root->AddChild(node); root->AddChild(node);
} }
/// @brief Write line
/// @param root
/// @param line
///
void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, AssDialogue *line) { void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, AssDialogue *line) {
// If it doesn't start at the end of previous, add blank // If it doesn't start at the end of previous, add blank
wxXmlNode *node,*subNode; wxXmlNode *node, *subNode;
if (prev && prev->End != line->Start) { if (prev && prev->End != line->Start) {
node = new wxXmlNode(wxXML_ELEMENT_NODE,"TextSample"); node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextSample");
node->AddAttribute("sampleTime","0" + prev->End.GetASSFormated(true)); node->AddAttribute("sampleTime", "0" + prev->End.GetASSFormated(true));
node->AddAttribute("xml:space","preserve"); node->AddAttribute("xml:space", "preserve");
subNode = new wxXmlNode(wxXML_TEXT_NODE,"",""); subNode = new wxXmlNode(wxXML_TEXT_NODE, "", "");
node->AddChild(subNode); node->AddChild(subNode);
root->AddChild(node); root->AddChild(node);
} }
// Generate and insert node // Generate and insert node
node = new wxXmlNode(wxXML_ELEMENT_NODE,"TextSample"); node = new wxXmlNode(wxXML_ELEMENT_NODE, "TextSample");
node->AddAttribute("sampleTime","0" + line->Start.GetASSFormated(true)); node->AddAttribute("sampleTime", "0" + line->Start.GetASSFormated(true));
node->AddAttribute("xml:space","preserve"); node->AddAttribute("xml:space", "preserve");
subNode = new wxXmlNode(wxXML_TEXT_NODE,"",line->Text); subNode = new wxXmlNode(wxXML_TEXT_NODE, "", line->Text);
node->AddChild(subNode); node->AddChild(subNode);
root->AddChild(node); root->AddChild(node);
@ -345,17 +277,12 @@ void TTXTSubtitleFormat::WriteLine(wxXmlNode *root, AssDialogue *line) {
prev = line; prev = line;
} }
/// @brief Converts whole file to TTXT
///
void TTXTSubtitleFormat::ConvertToTTXT () { void TTXTSubtitleFormat::ConvertToTTXT () {
// Convert
SortLines(); SortLines();
StripComments(); StripComments();
RecombineOverlaps(); RecombineOverlaps();
MergeIdentical(); MergeIdentical();
ConvertTags(1,"\r\n"); ConvertTags(1, "\r\n");
// Find last line // Find last line
AssTime lastTime; AssTime lastTime;
@ -376,5 +303,3 @@ void TTXTSubtitleFormat::ConvertToTTXT () {
diag->Comment = false; diag->Comment = false;
Line->push_back(diag); Line->push_back(diag);
} }

View file

@ -34,18 +34,14 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#ifndef AGI_PRE #ifndef AGI_PRE
#include <wx/xml/xml.h> #include <wx/xml/xml.h>
#endif #endif
#include "ass_dialogue.h"
#include "subtitle_format.h" #include "subtitle_format.h"
class AssDialogue;
/// DOCME /// DOCME
/// @class TTXTSubtitleFormat /// @class TTXTSubtitleFormat
@ -53,8 +49,6 @@
/// ///
/// DOCME /// DOCME
class TTXTSubtitleFormat : public SubtitleFormat { class TTXTSubtitleFormat : public SubtitleFormat {
private:
/// DOCME /// DOCME
int version; int version;
@ -68,20 +62,15 @@ private:
void ProcessHeader(wxXmlNode *node); void ProcessHeader(wxXmlNode *node);
void WriteHeader(wxXmlNode *root); void WriteHeader(wxXmlNode *root);
void WriteLine(wxXmlNode *root,AssDialogue *line); void WriteLine(wxXmlNode *root, AssDialogue *line);
void ConvertToTTXT(); void ConvertToTTXT();
public: public:
wxString GetName(); TTXTSubtitleFormat();
wxArrayString GetReadWildcards(); wxArrayString GetReadWildcards() const;
wxArrayString GetWriteWildcards(); wxArrayString GetWriteWildcards() const;
bool CanReadFile(wxString filename); void ReadFile(wxString const& filename, wxString const& forceEncoding);
void ReadFile(wxString filename,wxString forceEncoding); void WriteFile(wxString const& filename, wxString const& encoding);
bool CanWriteFile(wxString filename);
void WriteFile(wxString filename,wxString encoding);
}; };

View file

@ -34,114 +34,70 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "config.h" #include "config.h"
#include "subtitle_format_txt.h"
#include "ass_dialogue.h" #include "ass_dialogue.h"
#include "compat.h" #include "compat.h"
#include "dialog_text_import.h" #include "dialog_text_import.h"
#include "main.h" #include "main.h"
#include "subtitle_format_txt.h"
#include "text_file_reader.h" #include "text_file_reader.h"
#include "text_file_writer.h" #include "text_file_writer.h"
#include "version.h" #include "version.h"
/// @brief Can read? TXTSubtitleFormat::TXTSubtitleFormat()
/// @param filename : SubtitleFormat("Plain-Text")
/// @return {
///
bool TXTSubtitleFormat::CanReadFile(wxString filename) {
return (filename.Right(4).Lower() == ".txt");
} }
wxArrayString TXTSubtitleFormat::GetReadWildcards() const {
/// @brief Can write?
/// @param filename
/// @return
///
bool TXTSubtitleFormat::CanWriteFile(wxString filename) {
return (filename.Right(4).Lower() == ".txt" && filename.Right(11).Lower() != ".encore.txt" && filename.Right(16).Lower() != ".transtation.txt");
}
/// @brief Get name
/// @return
///
wxString TXTSubtitleFormat::GetName() {
return "Plain-Text";
}
/// @brief Get read wildcards
/// @return
///
wxArrayString TXTSubtitleFormat::GetReadWildcards() {
wxArrayString formats; wxArrayString formats;
formats.Add("txt"); formats.Add("txt");
return formats; return formats;
} }
wxArrayString TXTSubtitleFormat::GetWriteWildcards() const {
/// @brief Get write wildcards
/// @return
///
wxArrayString TXTSubtitleFormat::GetWriteWildcards() {
return GetReadWildcards(); return GetReadWildcards();
} }
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) {
/// @brief Read file using namespace std;
/// @param filename
/// @param encoding
/// @return
///
void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using namespace std;
// Import options
DialogTextImport dlg; DialogTextImport dlg;
if (dlg.ShowModal() == wxID_CANCEL) return; if (dlg.ShowModal() == wxID_CANCEL) return;
// Reader TextFileReader file(filename, encoding, false);
TextFileReader file(filename,encoding,false);
// Default
LoadDefault(false); LoadDefault(false);
// Data
wxString actor; wxString actor;
wxString separator = lagi_wxString(OPT_GET("Tool/Import/Text/Actor Separator")->GetString()); wxString separator = lagi_wxString(OPT_GET("Tool/Import/Text/Actor Separator")->GetString());
wxString comment = lagi_wxString(OPT_GET("Tool/Import/Text/Comment Starter")->GetString()); wxString comment = lagi_wxString(OPT_GET("Tool/Import/Text/Comment Starter")->GetString());
bool isComment = false;
int lines = 0; int lines = 0;
// Parse file // Parse file
AssDialogue *line = NULL;
while (file.HasMoreLines()) { while (file.HasMoreLines()) {
// Reads line
wxString value = file.ReadLineFromFile(); wxString value = file.ReadLineFromFile();
if(value.IsEmpty()) continue; if(value.empty()) continue;
// Check if this isn't a timecodes file // Check if this isn't a timecodes file
if (value.StartsWith("# timecode")) { if (value.StartsWith("# timecode"))
throw "File is a timecode file, cannot load as subtitles."; throw SubtitleFormatParseError("File is a timecode file, cannot load as subtitles.", 0);
}
// Read comment data // Read comment data
isComment = false; bool isComment = false;
if (comment != "" && value.Left(comment.Length()) == comment) { if (!comment.empty() && value.StartsWith(comment)) {
isComment = true; isComment = true;
value = value.Mid(comment.Length()); value = value.Mid(comment.size());
} }
// Read actor data // Read actor data
if (!isComment && separator != "") { if (!isComment && !separator.empty()) {
if (value[0] != ' ' && value[0] != '\t') { if (value[0] != ' ' && value[0] != '\t') {
int pos = value.Find(separator); int pos = value.Find(separator);
if (pos != wxNOT_FOUND) { if (pos != wxNOT_FOUND) {
@ -149,7 +105,6 @@ void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using na
actor.Trim(false); actor.Trim(false);
actor.Trim(true); actor.Trim(true);
value = value.Mid(pos+1); value = value.Mid(pos+1);
value.Trim(false);
} }
} }
} }
@ -157,16 +112,14 @@ void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using na
// Trim spaces at start // Trim spaces at start
value.Trim(false); value.Trim(false);
if (value.empty())
isComment = true;
// Sets line up // Sets line up
line = new AssDialogue; AssDialogue *line = new AssDialogue;
line->group = "[Events]"; line->group = "[Events]";
line->Style = "Default"; line->Style = "Default";
if (isComment) line->Actor = ""; line->Actor = isComment ? "" : line->Actor;
else line->Actor = actor;
if (value.IsEmpty()) {
line->Actor = "";
isComment = true;
}
line->Comment = isComment; line->Comment = isComment;
line->Text = value; line->Text = value;
line->Start.SetMS(0); line->Start.SetMS(0);
@ -179,7 +132,7 @@ void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using na
// No lines? // No lines?
if (lines == 0) { if (lines == 0) {
line = new AssDialogue; AssDialogue *line = new AssDialogue;
line->group = "[Events]"; line->group = "[Events]";
line->Style = "Default"; line->Style = "Default";
line->Start.SetMS(0); line->Start.SetMS(0);
@ -188,21 +141,15 @@ void TXTSubtitleFormat::ReadFile(wxString filename,wxString encoding) { using na
} }
} }
void TXTSubtitleFormat::WriteFile(wxString const& filename, wxString const& encoding) {
/// @brief Write file
/// @param filename
/// @param encoding
///
void TXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) { using namespace std;
size_t num_actor_names = 0, num_dialogue_lines = 0; size_t num_actor_names = 0, num_dialogue_lines = 0;
// Detect number of lines with Actor field filled out // Detect number of lines with Actor field filled out
for (list<AssEntry*>::iterator l = Line->begin(); l != Line->end(); ++l) { for (std::list<AssEntry*>::iterator l = Line->begin(); l != Line->end(); ++l) {
AssDialogue *dia = dynamic_cast<AssDialogue*>(*l); AssDialogue *dia = dynamic_cast<AssDialogue*>(*l);
if (dia && !dia->Comment) { if (dia && !dia->Comment) {
num_dialogue_lines++; num_dialogue_lines++;
if (!dia->Actor.IsEmpty()) if (!dia->Actor.empty())
num_actor_names++; num_actor_names++;
} }
} }
@ -215,7 +162,7 @@ void TXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) { using n
file.WriteLineToFile(wxString("# Exported by Aegisub ") + GetAegisubShortVersionString()); file.WriteLineToFile(wxString("# Exported by Aegisub ") + GetAegisubShortVersionString());
// Write the file // Write the file
for (list<AssEntry*>::iterator l = Line->begin(); l != Line->end(); ++l) { for (std::list<AssEntry*>::iterator l = Line->begin(); l != Line->end(); ++l) {
AssDialogue *dia = dynamic_cast<AssDialogue*>(*l); AssDialogue *dia = dynamic_cast<AssDialogue*>(*l);
if (dia) { if (dia) {
@ -244,7 +191,7 @@ void TXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) { using n
} }
out_line += out_text; out_line += out_text;
if (!out_text.IsEmpty()) { if (!out_text.empty()) {
file.WriteLineToFile(out_line); file.WriteLineToFile(out_line);
} }
} }
@ -255,5 +202,3 @@ void TXTSubtitleFormat::WriteFile(wxString filename,wxString encoding) { using n
} }
} }
} }

View file

@ -34,36 +34,20 @@
/// @ingroup subtitle_io /// @ingroup subtitle_io
/// ///
///////////
// Headers
#include "subtitle_format.h" #include "subtitle_format.h"
//////////////
// Prototypes
class AssDialogue;
/// DOCME /// DOCME
/// @class TXTSubtitleFormat /// @class TXTSubtitleFormat
/// @brief DOCME /// @brief DOCME
/// ///
/// DOCME /// DOCME
class TXTSubtitleFormat : public SubtitleFormat { class TXTSubtitleFormat : public SubtitleFormat {
private:
public: public:
wxString GetName(); TXTSubtitleFormat();
wxArrayString GetReadWildcards(); wxArrayString GetReadWildcards() const;
wxArrayString GetWriteWildcards(); wxArrayString GetWriteWildcards() const;
bool CanReadFile(wxString filename); bool CanWriteFile(wxString const& filename) const;
bool CanWriteFile(wxString filename); void ReadFile(wxString const& filename, wxString const& forceEncoding);
void ReadFile(wxString filename,wxString forceEncoding); void WriteFile(wxString const& filename, wxString const& encoding);
void WriteFile(wxString filename, wxString encoding = "");
}; };