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"
>
</File>
<File
RelativePath=".\src\text_file_writer.cpp"
>
</File>
<File
RelativePath=".\src\text_file_writer.h"
>
</File>
<File
RelativePath=".\src\time.cpp"
>

View File

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

View File

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

View File

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

View File

@ -49,18 +49,24 @@ namespace Aegilib {
};
// 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 SectionEntryPlain;
class SectionEntryDialogue;
class SectionEntryStyle;
class SectionEntryFile;
class SectionEntryRaw;
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
class SectionEntry {
@ -72,6 +78,7 @@ namespace Aegilib {
virtual SectionEntryType GetType() const =0;
static const SectionEntryPlainPtr GetAsPlain(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 SectionEntryFilePtr GetAsFile(const SectionEntryPtr &ptr);
static const SectionEntryRawPtr GetAsRaw(const SectionEntryPtr &ptr);

View File

@ -33,9 +33,11 @@
// Contact: mailto:amz@aegisub.net
//
#include "section.h"
#include "model.h"
#include "format_ass.h"
#include "../text_file_reader.h"
#include "../text_file_writer.h"
#include <iostream>
#include <wx/tokenzr.h>
using namespace Aegilib;
@ -78,10 +80,6 @@ void FormatHandlerASS::Load(wxInputStream &file,const String encoding)
// Make text file reader
TextFileReader reader(file,encoding);
// Debug
using namespace std;
cout << endl << "Dumping file:" << endl;
// Variables
int version = 1;
wxString curGroup = L"-";
@ -111,17 +109,44 @@ void FormatHandlerASS::Load(wxInputStream &file,const String encoding)
SectionEntryPtr entry = MakeEntry(cur,section,version);
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
class Model;
class TextFileWriter;
class SerializeText {
public:
virtual ~SerializeText(){}
virtual String ToText() const=0;
};
// Advanced Substation Alpha format handler
class FormatHandlerASS : public FormatHandler {
private:
Model &model;
SectionEntryPtr MakeEntry(const String &data,SectionPtr section,int version);
void ProcessGroup(String cur,String &curGroup,int &version);
Model &model;
void WriteSection(TextFileWriter &writer,SectionPtr section);
public:
FormatHandlerASS(Model &model);
~FormatHandlerASS();
void Load(wxInputStream &file,const String encoding);
void Save(wxOutputStream &file,const String encoding);
};
// Advanced Substation Alpha format
@ -76,7 +86,7 @@ namespace Aegilib {
};
// Dialogue
class DialogueASS : public SectionEntryDialogue {
class DialogueASS : public SectionEntryDialogue, public SerializeText {
private:
String text;
String style;
@ -88,6 +98,7 @@ namespace Aegilib {
bool isComment;
bool Parse(String data,int version);
String ToText() const;
public:
// Constructors
@ -123,7 +134,7 @@ namespace Aegilib {
};
// Style
class StyleASS : public SectionEntryStyle {
class StyleASS : public SectionEntryStyle, public SerializeText {
private:
String name;
String font;
@ -152,6 +163,7 @@ namespace Aegilib {
bool Parse(String data,int version);
int AlignSSAtoASS(int ssaAlignment);
int AlignASStoSSA(int assAlignment);
String ToText() const;
public:
// Constructors

View File

@ -134,3 +134,12 @@ bool DialogueASS::Parse(wxString rawData, int version)
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
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
void Model::Save(wxOutputStream &output,const FormatPtr format,const String encoding)
{
(void) output;
(void) format;
(void) encoding;
// Autodetect format
if (format == NULL) {
// 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
void Model::AddSection(String name)
@ -156,3 +154,31 @@ void Model::AddSection(String name)
if (prev) throw Exception(Exception::Section_Already_Exists);
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);
}
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
@ -91,7 +117,7 @@ bool Section::HasProperty(const String &key) const
//////////////////////
// Get property count
size_t Section::PropertyCount() const
size_t Section::GetPropertyCount() const
{
return properties.size();
}

View File

@ -57,6 +57,10 @@ const SectionEntryDialoguePtr SectionEntry::GetAsDialogue(const SectionEntryPtr
{
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)
{
return dynamic_pointer_cast<SectionEntryStyle>(ptr);

View File

@ -38,76 +38,38 @@
// Headers
#include <fstream>
#include "text_file_writer.h"
using namespace Aegilib;
///////////////
// Constructor
TextFileWriter::TextFileWriter(Aegilib::String _filename,Aegilib::String enc) {
TextFileWriter::TextFileWriter(wxOutputStream &stream,String enc)
: file(stream)
{
// Setup
open = false;
customConv = false;
IsFirst = true;
filename = _filename;
// Set encoding
encoding = enc;
if (encoding == _T("Local")) conv = &wxConvLocal;
if (encoding == _T("Local")) conv = shared_ptr<wxMBConv> (wxConvCurrent,NullDeleter());
else {
if (encoding.IsEmpty()) encoding = _T("UTF-8");
if (encoding == _T("US-ASCII")) encoding = _T("ISO-8859-1");
conv = new wxCSConv(encoding);
customConv = true;
conv = shared_ptr<wxMBConv> (new wxCSConv(encoding));
IsUnicode = encoding.Left(3) == _T("UTF");
}
// Open file
Open();
}
//////////////
// Destructor
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
void TextFileWriter::WriteLineToFile(Aegilib::String line,bool addLineBreak) {
// Make sure it's loaded
if (!open) Open();
// Add line break
wxString temp = line;
if (addLineBreak) temp += _T("\r\n");
@ -125,7 +87,7 @@ void TextFileWriter::WriteLineToFile(Aegilib::String line,bool addLineBreak) {
if (!buf.data())
return;
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
@ -134,7 +96,7 @@ void TextFileWriter::WriteLineToFile(Aegilib::String line,bool addLineBreak) {
if (!buf.data())
return;
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
#define TEXT_FILE_WRITER_H
#pragma once
#include "aegilib.h"
#include <wx/stream.h>
///////////
// Headers
#include <wx/wxprec.h>
#include <wx/string.h>
#include <fstream>
/////////
// Class
namespace Aegilib {
class TextFileWriter {
private:
wxString filename;
wxString encoding;
std::ofstream file;
wxOutputStream &file;
wxMBConv *conv;
bool customConv;
bool open;
shared_ptr<wxMBConv> conv;
bool Is16;
bool IsFirst;
bool IsUnicode;
void Open();
void Close();
void SetEncoding();
public:
TextFileWriter(Aegilib::String filename,Aegilib::String encoding=_T(""));
TextFileWriter(wxOutputStream &stream,String encoding=_T(""));
~TextFileWriter();
void WriteLineToFile(Aegilib::String line,bool addLineBreak=true);
};
#endif
};