Some far-from-complete ASS file writing.

Originally committed to SVN as r2035.
This commit is contained in:
Rodrigo Braz Monteiro 2008-03-13 05:39:03 +00:00
parent a3755cc6e4
commit 18e6684cff
14 changed files with 235 additions and 127 deletions

View file

@ -324,6 +324,14 @@
RelativePath=".\src\text_file_reader.h" RelativePath=".\src\text_file_reader.h"
> >
</File> </File>
<File
RelativePath=".\src\text_file_writer.cpp"
>
</File>
<File
RelativePath=".\src\text_file_writer.h"
>
</File>
<File <File
RelativePath=".\src\time.cpp" RelativePath=".\src\time.cpp"
> >

View file

@ -46,6 +46,7 @@ namespace Aegilib {
public: public:
virtual void Load(wxInputStream &file,const String encoding) = 0; virtual void Load(wxInputStream &file,const String encoding) = 0;
virtual void Save(wxOutputStream &file,const String encoding) = 0;
}; };
typedef shared_ptr<FormatHandler> FormatHandlerPtr; typedef shared_ptr<FormatHandler> FormatHandlerPtr;

View file

@ -35,6 +35,7 @@
#pragma once #pragma once
#include <list> #include <list>
#include <vector>
#include <wx/wfstream.h> #include <wx/wfstream.h>
#include "manipulator.h" #include "manipulator.h"
#include "section.h" #include "section.h"
@ -56,7 +57,7 @@ namespace Aegilib {
typedef shared_ptr<Format> FormatPtr; typedef shared_ptr<Format> FormatPtr;
private: private:
std::list<SectionPtr> sections; std::vector<SectionPtr> sections;
ActionStack undoStack; ActionStack undoStack;
ActionStack redoStack; ActionStack redoStack;
ViewList listeners; ViewList listeners;
@ -75,8 +76,10 @@ namespace Aegilib {
void LoadFile(const String filename,const String encoding=L""); void LoadFile(const String filename,const String encoding=L"");
void SaveFile(const String filename,const String encoding=L"UTF-8"); void SaveFile(const String filename,const String encoding=L"UTF-8");
SectionPtr GetSection(String name) const;
void AddSection(String name); void AddSection(String name);
SectionPtr GetSection(String name) const;
SectionPtr GetSectionByIndex(size_t index) const;
size_t GetSectionCount() const;
bool CanUndo(const String owner=L"") const; bool CanUndo(const String owner=L"") const;
bool CanRedo(const String owner=L"") const; bool CanRedo(const String owner=L"") const;

View file

@ -44,9 +44,8 @@ namespace Aegilib {
// Section class // Section class
class Section { class Section {
friend class shared_ptr<Section>;
private: private:
std::list<SectionEntryPtr> entries; std::vector<SectionEntryPtr> entries;
std::map<String,String> properties; std::map<String,String> properties;
String name; String name;
@ -54,17 +53,24 @@ namespace Aegilib {
Section(String name); Section(String name);
~Section() {} ~Section() {}
const String& GetName() const { return name; } // Section name
String SetName(const String& newName) { name = newName; } String SetName(const String& newName) { name = newName; }
const String& GetName() const { return name; }
// Script properties
void SetProperty(const String &key,const String &value); void SetProperty(const String &key,const String &value);
void UnsetProperty(const String &key); void UnsetProperty(const String &key);
String GetProperty(const String &key) const; String GetProperty(const String &key) const;
bool HasProperty(const String &key) const; bool HasProperty(const String &key) const;
size_t PropertyCount() const; size_t GetPropertyCount() const;
String GetPropertyName(size_t index) const; String GetPropertyName(size_t index) const;
// Entries
void AddEntry(SectionEntryPtr entry); void AddEntry(SectionEntryPtr entry);
void RemoveEntryByIndex(size_t index);
void RemoveEntry(SectionEntryPtr entry);
SectionEntryConstPtr GetEntry(size_t index) const;
size_t GetEntryCount() const;
}; };
typedef shared_ptr<Section> SectionPtr; typedef shared_ptr<Section> SectionPtr;

View file

@ -49,18 +49,24 @@ namespace Aegilib {
}; };
// Prototypes // Prototypes
class SectionEntryPlain;
typedef shared_ptr<SectionEntryPlain> SectionEntryPlainPtr;
class SectionEntryDialogue;
typedef shared_ptr<SectionEntryDialogue> SectionEntryDialoguePtr;
class SectionEntryStyle;
typedef shared_ptr<SectionEntryStyle> SectionEntryStylePtr;
class SectionEntryFile;
typedef shared_ptr<SectionEntryFile> SectionEntryFilePtr;
class SectionEntryRaw;
typedef shared_ptr<SectionEntryRaw> SectionEntryRawPtr;
class SectionEntry; class SectionEntry;
class SectionEntryPlain;
class SectionEntryDialogue;
class SectionEntryStyle;
class SectionEntryFile;
class SectionEntryRaw;
typedef shared_ptr<SectionEntry> SectionEntryPtr; typedef shared_ptr<SectionEntry> SectionEntryPtr;
typedef shared_ptr<SectionEntryPlain> SectionEntryPlainPtr;
typedef shared_ptr<SectionEntryDialogue> SectionEntryDialoguePtr;
typedef shared_ptr<SectionEntryStyle> SectionEntryStylePtr;
typedef shared_ptr<SectionEntryFile> SectionEntryFilePtr;
typedef shared_ptr<SectionEntryRaw> SectionEntryRawPtr;
typedef shared_ptr<const SectionEntry> SectionEntryConstPtr;
typedef shared_ptr<const SectionEntryPlain> SectionEntryPlainConstPtr;
typedef shared_ptr<const SectionEntryDialogue> SectionEntryDialogueConstPtr;
typedef shared_ptr<const SectionEntryStyle> SectionEntryStyleConstPtr;
typedef shared_ptr<const SectionEntryFile> SectionEntryFileConstPtr;
typedef shared_ptr<const SectionEntryRaw> SectionEntryRawConstPtr;
// Section entry class // Section entry class
class SectionEntry { class SectionEntry {
@ -72,6 +78,7 @@ namespace Aegilib {
virtual SectionEntryType GetType() const =0; virtual SectionEntryType GetType() const =0;
static const SectionEntryPlainPtr GetAsPlain(const SectionEntryPtr &ptr); static const SectionEntryPlainPtr GetAsPlain(const SectionEntryPtr &ptr);
static const SectionEntryDialoguePtr GetAsDialogue(const SectionEntryPtr &ptr); static const SectionEntryDialoguePtr GetAsDialogue(const SectionEntryPtr &ptr);
static const SectionEntryDialogueConstPtr GetAsDialogue(const SectionEntryConstPtr &ptr);
static const SectionEntryStylePtr GetAsStyle(const SectionEntryPtr &ptr); static const SectionEntryStylePtr GetAsStyle(const SectionEntryPtr &ptr);
static const SectionEntryFilePtr GetAsFile(const SectionEntryPtr &ptr); static const SectionEntryFilePtr GetAsFile(const SectionEntryPtr &ptr);
static const SectionEntryRawPtr GetAsRaw(const SectionEntryPtr &ptr); static const SectionEntryRawPtr GetAsRaw(const SectionEntryPtr &ptr);

View file

@ -33,9 +33,11 @@
// Contact: mailto:amz@aegisub.net // Contact: mailto:amz@aegisub.net
// //
#include "section.h"
#include "model.h" #include "model.h"
#include "format_ass.h" #include "format_ass.h"
#include "../text_file_reader.h" #include "../text_file_reader.h"
#include "../text_file_writer.h"
#include <iostream> #include <iostream>
#include <wx/tokenzr.h> #include <wx/tokenzr.h>
using namespace Aegilib; using namespace Aegilib;
@ -78,10 +80,6 @@ void FormatHandlerASS::Load(wxInputStream &file,const String encoding)
// Make text file reader // Make text file reader
TextFileReader reader(file,encoding); TextFileReader reader(file,encoding);
// Debug
using namespace std;
cout << endl << "Dumping file:" << endl;
// Variables // Variables
int version = 1; int version = 1;
wxString curGroup = L"-"; wxString curGroup = L"-";
@ -111,17 +109,44 @@ void FormatHandlerASS::Load(wxInputStream &file,const String encoding)
SectionEntryPtr entry = MakeEntry(cur,section,version); SectionEntryPtr entry = MakeEntry(cur,section,version);
if (entry) section->AddEntry(entry); if (entry) section->AddEntry(entry);
} }
// Debug
cout << "\nFinished reading file with version=" << version << ".\n";
cout << "Dumping properties:\n";
section = model.GetSection(_T("Script Info"));
size_t n = section->PropertyCount();
for (size_t i=0;i<n;i++) {
wxString name = section->GetPropertyName(i);
cout << name.mb_str(wxConvUTF8) << "=" << section->GetProperty(name).mb_str(wxConvUTF8) << endl;
} }
cout << "Done.\n" << endl;
/////////////////////
// Save file to disc
void FormatHandlerASS::Save(wxOutputStream &file,const String encoding)
{
// Make text file writer
TextFileWriter writer(file,encoding);
// Set up list of sections to write
wxArrayString sections;
sections.Add(L"Script Info");
sections.Add(L"V4+ Styles");
sections.Add(L"Events");
sections.Add(L"Fonts");
sections.Add(L"Graphics");
// Look for remaining sections
size_t totalSections = model.GetSectionCount();
for (size_t i=0;i<totalSections;i++) {
String name = model.GetSectionByIndex(i)->GetName();
if (sections.Index(name,false,false) == wxNOT_FOUND) sections.Add(name);
}
// Write sections
size_t len = sections.size();
for (size_t i=0;i<len;i++) {
// See if it exists
SectionPtr section = model.GetSection(sections[i]);
if (section) {
// Add a spacer
if (i != 0) writer.WriteLineToFile(_T(""));
// Write the section
WriteSection(writer,section);
}
}
} }
@ -264,3 +289,27 @@ void FormatHandlerASS::ProcessGroup(String cur,String &curGroup,int &version) {
} }
} }
} }
///////////////////////////////
// Write a section to the file
void FormatHandlerASS::WriteSection(TextFileWriter &writer,SectionPtr section)
{
// Write name
writer.WriteLineToFile(_T("[") + section->GetName() + _T("]"));
// Write properties
size_t props = section->GetPropertyCount();
for (size_t i=0;i<props;i++) {
String name = section->GetPropertyName(i);
writer.WriteLineToFile(name + _T(": ") + section->GetProperty(name));
}
// Write contents
size_t entries = section->GetEntryCount();
for (size_t i=0;i<entries;i++) {
SectionEntryConstPtr entry = section->GetEntry(i);
shared_ptr<const SerializeText> serial = dynamic_pointer_cast<const SerializeText>(entry);
writer.WriteLineToFile(serial->ToText());
}
}

View file

@ -44,19 +44,29 @@ namespace Aegilib {
// Prototypes // Prototypes
class Model; class Model;
class TextFileWriter;
class SerializeText {
public:
virtual ~SerializeText(){}
virtual String ToText() const=0;
};
// Advanced Substation Alpha format handler // Advanced Substation Alpha format handler
class FormatHandlerASS : public FormatHandler { class FormatHandlerASS : public FormatHandler {
private: private:
Model &model;
SectionEntryPtr MakeEntry(const String &data,SectionPtr section,int version); SectionEntryPtr MakeEntry(const String &data,SectionPtr section,int version);
void ProcessGroup(String cur,String &curGroup,int &version); void ProcessGroup(String cur,String &curGroup,int &version);
Model &model; void WriteSection(TextFileWriter &writer,SectionPtr section);
public: public:
FormatHandlerASS(Model &model); FormatHandlerASS(Model &model);
~FormatHandlerASS(); ~FormatHandlerASS();
void Load(wxInputStream &file,const String encoding); void Load(wxInputStream &file,const String encoding);
void Save(wxOutputStream &file,const String encoding);
}; };
// Advanced Substation Alpha format // Advanced Substation Alpha format
@ -76,7 +86,7 @@ namespace Aegilib {
}; };
// Dialogue // Dialogue
class DialogueASS : public SectionEntryDialogue { class DialogueASS : public SectionEntryDialogue, public SerializeText {
private: private:
String text; String text;
String style; String style;
@ -88,6 +98,7 @@ namespace Aegilib {
bool isComment; bool isComment;
bool Parse(String data,int version); bool Parse(String data,int version);
String ToText() const;
public: public:
// Constructors // Constructors
@ -123,7 +134,7 @@ namespace Aegilib {
}; };
// Style // Style
class StyleASS : public SectionEntryStyle { class StyleASS : public SectionEntryStyle, public SerializeText {
private: private:
String name; String name;
String font; String font;
@ -152,6 +163,7 @@ namespace Aegilib {
bool Parse(String data,int version); bool Parse(String data,int version);
int AlignSSAtoASS(int ssaAlignment); int AlignSSAtoASS(int ssaAlignment);
int AlignASStoSSA(int assAlignment); int AlignASStoSSA(int assAlignment);
String ToText() const;
public: public:
// Constructors // Constructors

View file

@ -134,3 +134,12 @@ bool DialogueASS::Parse(wxString rawData, int version)
return true; return true;
} }
/////////////
// Serialize
String DialogueASS::ToText() const
{
String final = L"Dialogue";
return final;
}

View file

@ -163,3 +163,12 @@ int StyleASS::AlignASStoSSA(int assAlignment)
// TODO // TODO
return assAlignment; return assAlignment;
} }
/////////////
// Serialize
String StyleASS::ToText() const
{
String final = L"Style";
return final;
}

View file

@ -109,10 +109,20 @@ void Model::Load(wxInputStream &input,const FormatPtr format,const String encodi
// Save subtitles // Save subtitles
void Model::Save(wxOutputStream &output,const FormatPtr format,const String encoding) void Model::Save(wxOutputStream &output,const FormatPtr format,const String encoding)
{ {
(void) output; // Autodetect format
(void) format; if (format == NULL) {
(void) encoding;
// TODO // TODO
// No format found
throw Exception(Exception::No_Format_Handler);
}
// Get handler
FormatHandlerPtr handler = format->GetHandler(*this);
if (!handler) throw Exception(Exception::No_Format_Handler);
// Load
handler->Save(output,encoding);
} }
@ -136,18 +146,6 @@ void Model::SaveFile(const String filename,const String encoding)
} }
//////////////////
// Gets a section
SectionPtr Model::GetSection(String name) const
{
std::list<SectionPtr>::const_iterator cur;
for (cur=sections.begin();cur!=sections.end();cur++) {
if ((*cur)->GetName() == name) return *cur;
}
return SectionPtr();
}
///////////////////////// /////////////////////////
// Inserts a new section // Inserts a new section
void Model::AddSection(String name) void Model::AddSection(String name)
@ -156,3 +154,31 @@ void Model::AddSection(String name)
if (prev) throw Exception(Exception::Section_Already_Exists); if (prev) throw Exception(Exception::Section_Already_Exists);
sections.push_back(SectionPtr(new Section(name))); sections.push_back(SectionPtr(new Section(name)));
} }
//////////////////
// Gets a section
SectionPtr Model::GetSection(String name) const
{
size_t len = sections.size();
for (size_t i=0;i<len;i++) {
if (sections[i]->GetName() == name) return sections[i];
}
return SectionPtr();
}
////////////////////////
// Get section by index
SectionPtr Model::GetSectionByIndex(size_t index) const
{
return sections.at(index);
}
/////////////////////
// Get section count
size_t Model::GetSectionCount() const
{
return sections.size();
}

View file

@ -53,6 +53,32 @@ void Section::AddEntry(SectionEntryPtr entry)
entries.push_back(entry); entries.push_back(entry);
} }
void Section::RemoveEntryByIndex(size_t index)
{
entries.erase(entries.begin()+index);
}
void Section::RemoveEntry(SectionEntryPtr entry)
{
size_t len = entries.size();
for (size_t i=0;i<len;i++) {
if (entries[i] == entry) {
entries.erase(entries.begin()+i);
return;
}
}
}
SectionEntryConstPtr Section::GetEntry(size_t index) const
{
return entries[index];
}
size_t Section::GetEntryCount() const
{
return entries.size();
}
////////////////// //////////////////
// Set a property // Set a property
@ -91,7 +117,7 @@ bool Section::HasProperty(const String &key) const
////////////////////// //////////////////////
// Get property count // Get property count
size_t Section::PropertyCount() const size_t Section::GetPropertyCount() const
{ {
return properties.size(); return properties.size();
} }

View file

@ -57,6 +57,10 @@ const SectionEntryDialoguePtr SectionEntry::GetAsDialogue(const SectionEntryPtr
{ {
return dynamic_pointer_cast<SectionEntryDialogue>(ptr); return dynamic_pointer_cast<SectionEntryDialogue>(ptr);
} }
const SectionEntryDialogueConstPtr SectionEntry::GetAsDialogue(const SectionEntryConstPtr &ptr)
{
return dynamic_pointer_cast<const SectionEntryDialogue>(ptr);
}
const SectionEntryStylePtr SectionEntry::GetAsStyle(const SectionEntryPtr &ptr) const SectionEntryStylePtr SectionEntry::GetAsStyle(const SectionEntryPtr &ptr)
{ {
return dynamic_pointer_cast<SectionEntryStyle>(ptr); return dynamic_pointer_cast<SectionEntryStyle>(ptr);

View file

@ -38,76 +38,38 @@
// Headers // Headers
#include <fstream> #include <fstream>
#include "text_file_writer.h" #include "text_file_writer.h"
using namespace Aegilib;
/////////////// ///////////////
// Constructor // Constructor
TextFileWriter::TextFileWriter(Aegilib::String _filename,Aegilib::String enc) { TextFileWriter::TextFileWriter(wxOutputStream &stream,String enc)
: file(stream)
{
// Setup // Setup
open = false;
customConv = false;
IsFirst = true; IsFirst = true;
filename = _filename;
// Set encoding // Set encoding
encoding = enc; encoding = enc;
if (encoding == _T("Local")) conv = &wxConvLocal; if (encoding == _T("Local")) conv = shared_ptr<wxMBConv> (wxConvCurrent,NullDeleter());
else { else {
if (encoding.IsEmpty()) encoding = _T("UTF-8"); if (encoding.IsEmpty()) encoding = _T("UTF-8");
if (encoding == _T("US-ASCII")) encoding = _T("ISO-8859-1"); if (encoding == _T("US-ASCII")) encoding = _T("ISO-8859-1");
conv = new wxCSConv(encoding); conv = shared_ptr<wxMBConv> (new wxCSConv(encoding));
customConv = true;
IsUnicode = encoding.Left(3) == _T("UTF"); IsUnicode = encoding.Left(3) == _T("UTF");
} }
// Open file
Open();
} }
////////////// //////////////
// Destructor // Destructor
TextFileWriter::~TextFileWriter() { TextFileWriter::~TextFileWriter() {
Close();
}
/////////////
// Open file
void TextFileWriter::Open() {
// Open file
if (open) return;
#ifdef WIN32
file.open(filename.wc_str(),std::ios::out | std::ios::binary | std::ios::trunc);
#else
file.open(wxFNCONV(filename),std::ios::out | std::ios::binary | std::ios::trunc);
#endif
if (!file.is_open()) {
throw _T("Failed opening file for writing.");
}
open = true;
// Set encoding
SetEncoding();
}
//////////////
// Close file
void TextFileWriter::Close() {
if (!open) return;
file.close();
open = false;
if (customConv) delete conv;
} }
///////////////// /////////////////
// Write to file // Write to file
void TextFileWriter::WriteLineToFile(Aegilib::String line,bool addLineBreak) { void TextFileWriter::WriteLineToFile(Aegilib::String line,bool addLineBreak) {
// Make sure it's loaded
if (!open) Open();
// Add line break // Add line break
wxString temp = line; wxString temp = line;
if (addLineBreak) temp += _T("\r\n"); if (addLineBreak) temp += _T("\r\n");
@ -125,7 +87,7 @@ void TextFileWriter::WriteLineToFile(Aegilib::String line,bool addLineBreak) {
if (!buf.data()) if (!buf.data())
return; return;
size_t len = wcslen(buf.data()); size_t len = wcslen(buf.data());
file.write((const char*)buf.data(),(std::streamsize)len*sizeof(wchar_t)); file.Write((const char*)buf.data(),(std::streamsize)len*sizeof(wchar_t));
} }
// 8-bit // 8-bit
@ -134,7 +96,7 @@ void TextFileWriter::WriteLineToFile(Aegilib::String line,bool addLineBreak) {
if (!buf.data()) if (!buf.data())
return; return;
size_t len = strlen(buf.data()); size_t len = strlen(buf.data());
file.write(buf.data(),(std::streamsize)len); file.Write(buf.data(),(std::streamsize)len);
} }
} }

View file

@ -34,42 +34,28 @@
// //
#ifndef TEXT_FILE_WRITER_H #pragma once
#define TEXT_FILE_WRITER_H #include "aegilib.h"
#include <wx/stream.h>
/////////// namespace Aegilib {
// Headers
#include <wx/wxprec.h>
#include <wx/string.h>
#include <fstream>
/////////
// Class
class TextFileWriter { class TextFileWriter {
private: private:
wxString filename;
wxString encoding; wxString encoding;
std::ofstream file; wxOutputStream &file;
wxMBConv *conv; shared_ptr<wxMBConv> conv;
bool customConv;
bool open;
bool Is16; bool Is16;
bool IsFirst; bool IsFirst;
bool IsUnicode; bool IsUnicode;
void Open();
void Close();
void SetEncoding(); void SetEncoding();
public: public:
TextFileWriter(Aegilib::String filename,Aegilib::String encoding=_T("")); TextFileWriter(wxOutputStream &stream,String encoding=_T(""));
~TextFileWriter(); ~TextFileWriter();
void WriteLineToFile(Aegilib::String line,bool addLineBreak=true); void WriteLineToFile(Aegilib::String line,bool addLineBreak=true);
}; };
};
#endif