Subs lib can now mostly read and write SSA, ASS and ASS2 files, except for a few features missing: hard comments, unknown sections and files are stripped

Originally committed to SVN as r2037.
This commit is contained in:
Rodrigo Braz Monteiro 2008-03-13 07:05:53 +00:00
parent e6b2bfd74b
commit 433997b43e
18 changed files with 396 additions and 45 deletions

View File

@ -235,6 +235,10 @@
RelativePath=".\include\aegilib\utils.h"
>
</File>
<File
RelativePath=".\include\aegilib\version.h"
>
</File>
<File
RelativePath=".\include\aegilib\view.h"
>
@ -344,6 +348,10 @@
RelativePath=".\src\utils.cpp"
>
</File>
<File
RelativePath=".\src\version.cpp"
>
</File>
</Filter>
<Filter
Name="Formats"

View File

@ -51,3 +51,4 @@
#include "aegitime.h"
#include "colour.h"
#include "utils.h"
#include "version.h"

View File

@ -48,9 +48,9 @@ namespace Aegilib {
Time(int ms) { (void)ms; }
void SetMS(int milliseconds) { ms = milliseconds; }
int GetMS() { return ms; }
int GetMS() const { return ms; }
String GetString(int ms_precision,int h_precision);
String GetString(int ms_precision,int h_precision) const;
void Parse(String data);
};

View File

@ -63,6 +63,7 @@ namespace Aegilib {
unsigned char GetAlpha() const { return a; }
void Parse(String str,bool reverse);
String GetVBHex(bool withAlpha=false,bool withHeader=true,bool withFooter=true) const;
};
};

View File

@ -72,4 +72,12 @@ namespace Aegilib {
// Convert a string to an integer
int StringToInt(const String &str);
// Number to string functions
String PrettyFloat(String src);
String PrettyFloatF(float src);
String PrettyFloatD(double src);
String FloatToString(double value);
String IntegerToString(int value);
String PrettySize(int bytes);
};

View File

@ -0,0 +1,55 @@
// Copyright (c) 2008, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB/AEGILIB
//
// Website: http://www.aegisub.net
// Contact: mailto:amz@aegisub.net
//
#pragma once
#include "aegistring.h"
////////////////////
// Helper functions
namespace Aegilib {
// Version
String GetLibraryName();
String GetLibraryVersionString();
String GetLibraryURL();
// Host application
void SetHostApplicationName(const String name);
void SetHostApplicationURL(const String name);
String GetHostApplicationName();
String GetHostApplicationURL();
};

View File

@ -106,3 +106,16 @@ void Colour::Parse(String value,bool reverse)
b = aux;
}
}
/////////////////////////////
// Generate Visual Basic hex
String Colour::GetVBHex(bool withAlpha,bool withHeader,bool withFooter) const
{
wxString work;
if (withHeader) work += _T("&H");
if (withAlpha) work += wxString::Format(_T("%02X"),a);
work += wxString::Format(_T("%02X%02X%02X"),b,g,r);
if (withFooter) work += _T("&");
return work;
}

View File

@ -57,6 +57,8 @@ void FormatManager::AddFormat(const FormatPtr format)
void FormatManager::InitializeFormats()
{
formats.push_back(FormatPtr(new FormatASS));
formats.push_back(FormatPtr(new FormatSSA));
formats.push_back(FormatPtr(new FormatASS2));
}

View File

@ -36,6 +36,7 @@
#include "section.h"
#include "model.h"
#include "format_ass.h"
#include "version.h"
#include "../text_file_reader.h"
#include "../text_file_writer.h"
#include <iostream>
@ -43,13 +44,26 @@
using namespace Aegilib;
//////////////
// Extensions
///////
// SSA
StringArray FormatSSA::GetReadExtensions() const
{
StringArray final;
final.push_back(L".ssa");
return final;
}
StringArray FormatSSA::GetWriteExtensions() const
{
return GetReadExtensions();
}
///////
// ASS
StringArray FormatASS::GetReadExtensions() const
{
StringArray final;
final.push_back(L".ass");
final.push_back(L".ssa");
return final;
}
StringArray FormatASS::GetWriteExtensions() const
@ -58,10 +72,24 @@ StringArray FormatASS::GetWriteExtensions() const
}
////////
// ASS2
StringArray FormatASS2::GetReadExtensions() const
{
StringArray final;
final.push_back(L".ass");
return final;
}
StringArray FormatASS2::GetWriteExtensions() const
{
return GetReadExtensions();
}
///////////////
// Constructor
FormatHandlerASS::FormatHandlerASS(Model &_model)
: model(_model)
FormatHandlerASS::FormatHandlerASS(Model &_model,int version)
: model(_model), formatVersion(version)
{
}
@ -296,7 +324,20 @@ void FormatHandlerASS::ProcessGroup(String cur,String &curGroup,int &version) {
void FormatHandlerASS::WriteSection(TextFileWriter &writer,SectionPtr section)
{
// Write name
writer.WriteLineToFile(_T("[") + section->GetName() + _T("]"));
wxString name = section->GetName();
writer.WriteLineToFile(_T("[") + name + _T("]"));
// Write program and library credits
if (name == _T("Script Info")) {
wxString programName = GetHostApplicationName();
wxString programURL = GetHostApplicationURL();
wxString libVersion = GetLibraryVersionString();
wxString libURL = GetLibraryURL();
writer.WriteLineToFile(_T("; Script generated by ") + programName);
if (!programURL.IsEmpty()) writer.WriteLineToFile(_T("; ") + programURL);
writer.WriteLineToFile(_T("; With ") + libVersion);
if (programURL != libURL) writer.WriteLineToFile(_T("; ") + libURL);
}
// Write properties
size_t props = section->GetPropertyCount();
@ -310,6 +351,6 @@ void FormatHandlerASS::WriteSection(TextFileWriter &writer,SectionPtr section)
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());
writer.WriteLineToFile(serial->ToText(formatVersion));
}
}

View File

@ -46,36 +46,35 @@ namespace Aegilib {
class Model;
class TextFileWriter;
// Interface to serialize classes
class SerializeText {
public:
virtual ~SerializeText(){}
virtual String ToText() const=0;
virtual String ToText(int param) const=0;
};
// Advanced Substation Alpha format handler
class FormatHandlerASS : public FormatHandler {
private:
Model &model;
int formatVersion;
SectionEntryPtr MakeEntry(const String &data,SectionPtr section,int version);
void ProcessGroup(String cur,String &curGroup,int &version);
void WriteSection(TextFileWriter &writer,SectionPtr section);
public:
FormatHandlerASS(Model &model);
FormatHandlerASS(Model &model,int version);
~FormatHandlerASS();
void Load(wxInputStream &file,const String encoding);
void Save(wxOutputStream &file,const String encoding);
};
// Advanced Substation Alpha format
class FormatASS : public Format {
// Advanced Substation Alpha format base class
class FormatASSFamily : public Format {
public:
String GetName() const { return L"Advanced Substation Alpha"; }
StringArray GetReadExtensions() const;
StringArray GetWriteExtensions() const;
FormatHandlerPtr GetHandler(Model &model) const { return FormatHandlerPtr(new FormatHandlerASS(model)); }
virtual ~FormatASSFamily() {}
bool CanStoreText() const { return true; }
bool CanUseTime() const { return true; }
@ -85,6 +84,33 @@ namespace Aegilib {
bool HasActors() const { return true; }
};
// Substation Alpha
class FormatSSA : public FormatASSFamily {
public:
FormatHandlerPtr GetHandler(Model &model) const { return FormatHandlerPtr(new FormatHandlerASS(model,0)); }
String GetName() const { return L"Substation Alpha"; }
StringArray GetReadExtensions() const;
StringArray GetWriteExtensions() const;
};
// Advanced Substation Alpha
class FormatASS : public FormatASSFamily {
public:
FormatHandlerPtr GetHandler(Model &model) const { return FormatHandlerPtr(new FormatHandlerASS(model,1)); }
String GetName() const { return L"Advanced Substation Alpha"; }
StringArray GetReadExtensions() const;
StringArray GetWriteExtensions() const;
};
// Advanced Substation Alpha 2
class FormatASS2 : public FormatASSFamily {
public:
FormatHandlerPtr GetHandler(Model &model) const { return FormatHandlerPtr(new FormatHandlerASS(model,2)); }
String GetName() const { return L"Advanced Substation Alpha 2"; }
StringArray GetReadExtensions() const;
StringArray GetWriteExtensions() const;
};
// Dialogue
class DialogueASS : public SectionEntryDialogue, public SerializeText {
private:
@ -98,7 +124,7 @@ namespace Aegilib {
bool isComment;
bool Parse(String data,int version);
String ToText() const;
String ToText(int param) const;
public:
// Constructors
@ -161,9 +187,9 @@ namespace Aegilib {
float shadow_w;
bool Parse(String data,int version);
int AlignSSAtoASS(int ssaAlignment);
int AlignASStoSSA(int assAlignment);
String ToText() const;
int AlignSSAtoASS(int ssaAlignment) const;
int AlignASStoSSA(int assAlignment) const;
String ToText(int param) const;
public:
// Constructors

View File

@ -138,8 +138,33 @@ bool DialogueASS::Parse(wxString rawData, int version)
/////////////
// Serialize
String DialogueASS::ToText() const
String DialogueASS::ToText(int version) const
{
String final = L"Dialogue";
// Prepare
wxString final = _T("");
// Write comment or dialogue
if (isComment) final = _T("Comment: ");
else final = _T("Dialogue: ");
// Write layer or marked
if (version >= 1) final += wxString::Format(_T("%01i,"),layer);
else final += _T("Marked=0,");
// Write times, style and actor
final += start.GetString(2,1) + _T(",") + end.GetString(2,1) + _T(",") + style + _T(",") + actor + _T(",");
// Write margins
if (version <= 1) final += wxString::Format(_T("%04i,%04i,%04i,"),margin[0],margin[1],margin[2]);
else final += wxString::Format(_T("%04i,%04i,%04i,%04i,"),margin[0],margin[1],margin[2],margin[3]);
// Write effect and text
final += effect + _T(",") + text;
// Make sure that final has no line breaks
final.Replace(_T("\n"),_T(""));
final.Replace(_T("\r"),_T(""));
// Return final
return final;
}

View File

@ -35,6 +35,7 @@
#include "format_ass.h"
#include "tokenizer.h"
#include "utils.h"
using namespace Aegilib;
@ -124,6 +125,7 @@ bool StyleASS::Parse(String data,int version)
encoding = tkn.GetInt();
// Read relative to
relativeTo = 0;
if (version == 2) relativeTo = tkn.GetInt();
// End
@ -139,7 +141,7 @@ bool StyleASS::Parse(String data,int version)
////////////////////////////////
// Convert SSA alignment to ASS
int StyleASS::AlignSSAtoASS(int align)
int StyleASS::AlignSSAtoASS(int align) const
{
switch(align) {
case 1: return 1;
@ -158,17 +160,69 @@ int StyleASS::AlignSSAtoASS(int align)
////////////////////////////////
// Convert ASS alignment to SSA
int StyleASS::AlignASStoSSA(int assAlignment)
int StyleASS::AlignASStoSSA(int align) const
{
// TODO
return assAlignment;
switch (align) {
case 1: return 1;
case 2: return 2;
case 3: return 3;
case 4: return 9;
case 5: return 10;
case 6: return 11;
case 7: return 5;
case 8: return 6;
case 9: return 7;
default: return 2;
}
}
/////////////
// Serialize
String StyleASS::ToText() const
String StyleASS::ToText(int version) const
{
String final = L"Style";
// Final string
wxString final;
// Calculate colour offset
int cOff = 0;
if (version >= 1) cOff = 1;
// Calculate alignment
int align = alignment;
if (version == 0) align = AlignASStoSSA(align);
// Name, font, fontsize, colours, bold, italics
final = wxString::Format(_T("Style: %s,%s,%s,%s,%s,%s,%s,%i,%i,"),
name.c_str(), font.c_str(), PrettyFloatD(fontSize).c_str(),
colour[0].GetVBHex(true,true,false).c_str(), colour[1].GetVBHex(true,true,false).c_str(),
colour[2+cOff].GetVBHex(true,true,false).c_str(), colour[3+cOff].GetVBHex(true,true,false).c_str(),
(bold? -1 : 0), (italic ? -1 : 0));
// ASS-only
final += wxString::Format(_T("%i,%i,%s,%s,%s,%s,"),
(underline?-1:0),(strikeout?-1:0),PrettyFloatD(scalex).c_str(),PrettyFloatD(scaley).c_str(),
PrettyFloatD(spacing).c_str(),PrettyFloatD(angle).c_str());
// Borderstyle, outline width, shadow width, alignment, first three margins
final += wxString::Format(_T("%i,%s,%s,%i,%i,%i,%i,"),
borderStyle,PrettyFloatD(outline_w).c_str(),PrettyFloatD(shadow_w).c_str(),
align,margin[0],margin[1],margin[2]);
// Fourth margin for ASS2 only
if (version == 2) final += wxString::Format(_T("%i,"),margin[3]);
// Alpha level for SSA only
// TODO: write something relevant?
if (version == 0) final += wxString::Format(_T("%i,"),0);
// Encoding
final += wxString::Format(_T("%i"),encoding);
// Relative-to for ASS2 only
if (version == 2) final += wxString::Format(_T(",%i"),relativeTo);
// Done
return final;
}

View File

@ -48,16 +48,7 @@ TextFileWriter::TextFileWriter(wxOutputStream &stream,String enc)
{
// Setup
IsFirst = true;
// Set encoding
encoding = enc;
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 = shared_ptr<wxMBConv> (new wxCSConv(encoding));
IsUnicode = encoding.Left(3) == _T("UTF");
}
SetEncoding(enc);
}
@ -103,12 +94,20 @@ void TextFileWriter::WriteLineToFile(Aegilib::String line,bool addLineBreak) {
////////////////
// Set encoding
void TextFileWriter::SetEncoding() {
void TextFileWriter::SetEncoding(String enc) {
// Prepare
Is16 = false;
// UTF-16
if (encoding.Left(6) == _T("UTF-16")) {
Is16 = true;
// Set encoding
encoding = enc;
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 = shared_ptr<wxMBConv> (new wxCSConv(encoding));
IsUnicode = encoding.Left(3) == _T("UTF");
if (encoding.Left(6) == _T("UTF-16")) {
Is16 = true;
}
}
}

View File

@ -50,7 +50,7 @@ namespace Aegilib {
bool IsFirst;
bool IsUnicode;
void SetEncoding();
void SetEncoding(String encoding);
public:
TextFileWriter(wxOutputStream &stream,String encoding=_T(""));

View File

@ -39,7 +39,7 @@ using namespace Aegilib;
//////////////////////
// Generates a string
String Time::GetString(int ms_precision,int h_precision)
String Time::GetString(int ms_precision,int h_precision) const
{
// Enforce sanity
ms_precision = Mid(0,ms_precision,3);

View File

@ -47,3 +47,38 @@ int Aegilib::StringToInt(const String &str)
str.ToLong(&temp);
return (int) temp;
}
////////////////
// Pretty float
String Aegilib::PrettyFloat(String src) {
if (src.Contains(_T("."))) {
size_t len = src.Length();
while (src.Right(1) == _T("0")) {
len--;
src.Truncate(len);
}
if (src.Right(1) == _T(".")) {
len--;
src.Truncate(len);
}
}
return src;
}
String Aegilib::PrettyFloatF(float src) { return Aegilib::PrettyFloat(wxString::Format(_T("%f"),src)); }
String Aegilib::PrettyFloatD(double src) { return Aegilib::PrettyFloat(wxString::Format(_T("%f"),src)); }
///////////////////
// Float to string
String Aegilib::FloatToString(double value) {
return PrettyFloat(wxString::Format(_T("%f"),value));
}
/////////////////
// Int to string
String Aegilib::IntegerToString(int value) {
return wxString::Format(_T("%i"),value);
}

82
aegilib/src/version.cpp Normal file
View File

@ -0,0 +1,82 @@
// Copyright (c) 2008, Rodrigo Braz Monteiro
// All rights reserved.
//
// Redistribution and use in source and binary forms, with or without
// modification, are permitted provided that the following conditions are met:
//
// * Redistributions of source code must retain the above copyright notice,
// this list of conditions and the following disclaimer.
// * Redistributions in binary form must reproduce the above copyright notice,
// this list of conditions and the following disclaimer in the documentation
// and/or other materials provided with the distribution.
// * Neither the name of the Aegisub Group nor the names of its contributors
// may be used to endorse or promote products derived from this software
// without specific prior written permission.
//
// THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
// AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
// IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
// ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT OWNER OR CONTRIBUTORS BE
// LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
// CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
// SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
// INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
// CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
// ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
// POSSIBILITY OF SUCH DAMAGE.
//
// -----------------------------------------------------------------------------
//
// AEGISUB/AEGILIB
//
// Website: http://www.aegisub.net
// Contact: mailto:amz@aegisub.net
//
#include "version.h"
#include "tr1.h"
using namespace Aegilib;
////////////////
// Library data
String Aegilib::GetLibraryName()
{
return _T("Aegilib");
}
String Aegilib::GetLibraryVersionString()
{
return _T("Aegilib v0.x - EXPERIMENTAL");
}
String Aegilib::GetLibraryURL()
{
return _T("http://www.aegisub.net");
}
/////////////////////////
// Host application data
static shared_ptr<String> hostName;
static shared_ptr<String> hostURL;
void Aegilib::SetHostApplicationName(const String name)
{
if (!hostName) hostName = shared_ptr<String> (new String());
*hostName = name;
}
void Aegilib::SetHostApplicationURL(const String url)
{
if (!hostURL) hostName = shared_ptr<String> (new String());
*hostURL = url;
}
String Aegilib::GetHostApplicationName()
{
if (hostName) return *hostName;
return L"unknown application";
}
String Aegilib::GetHostApplicationURL()
{
if (hostURL) return *hostURL;
return L"";
}

View File

@ -48,6 +48,7 @@ int main () {
try {
// Set up the lib
FormatManager::InitializeFormats();
Aegilib::SetHostApplicationName(L"Aegilib test program");
// Subtitles model
Model subs;