Subs library should now be able to fully parse ASS files, except for file attachments. It's also missing any way of parsing override tags, and the interface accessors are incomplete.

Originally committed to SVN as r2031.
This commit is contained in:
Rodrigo Braz Monteiro 2008-03-13 00:51:31 +00:00
parent f5746ee0fc
commit d70d4407e7
11 changed files with 242 additions and 48 deletions

View file

@ -227,6 +227,10 @@
RelativePath=".\include\aegilib\tokenizer.h"
>
</File>
<File
RelativePath=".\include\aegilib\utils.h"
>
</File>
<File
RelativePath=".\include\aegilib\view.h"
>
@ -324,6 +328,10 @@
RelativePath=".\src\tokenizer.cpp"
>
</File>
<File
RelativePath=".\src\utils.cpp"
>
</File>
</Filter>
<Filter
Name="Formats"

View file

@ -49,16 +49,4 @@
#include "section_entry_style.h"
#include "aegitime.h"
#include "colour.h"
//////////
// Macros
#ifndef MAX
#define MAX(a,b) (((a) > (b)) ? (a) : (b))
#endif
#ifndef MIN
#define MIN(a,b) (((a) < (b)) ? (a) : (b))
#endif
#ifndef MID
#define MID(a,b,c) MIN(MAX((a),(b)),(c))
#endif
#include "utils.h"

View file

@ -37,6 +37,7 @@
#include "aegistring.h"
#include "section_entry.h"
#include <list>
#include <map>
namespace Aegilib {
@ -44,14 +45,22 @@ namespace Aegilib {
class Section {
private:
std::list<SectionEntry*> entries;
std::map<String,String> properties;
String name;
public:
Section(String name);
~Section();
String GetName() const { return name; }
String SetName(String newName) { name = newName; }
const String& GetName() const { return name; }
String SetName(const String& newName) { name = newName; }
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;
String GetPropertyName(size_t index) const;
void AddEntry(SectionEntry *entry);
};

View file

@ -0,0 +1,75 @@
// 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 "aegilib.h"
/////////////
// Templates
// Returns the largest of two values
template <typename T>
T Max(T a,T b)
{
if (b < a) return a;
return b;
}
// Returns the smallest of two values
template <typename T>
T Min(T a,T b)
{
if (a < b) return a;
return b;
}
// Returns b, but limiting it to the interval [a,c]
template <typename T>
T Mid(T a,T b,T c)
{
return Min(Max(a,b),c);
}
////////////////////
// Helper functions
namespace Aegilib {
// Convert a string to an integer
int StringToInt(const String &str);
};

View file

@ -62,10 +62,10 @@ Colour::Colour (int red,int green,int blue,int alpha)
////////////////////////
// Set colour component
void Colour::SetRed(int red) { r = (unsigned char) MID(0,red,255); }
void Colour::SetGreen(int green) { g = (unsigned char) MID(0,green,255); }
void Colour::SetBlue(int blue) { b = (unsigned char) MID(0,blue,255); }
void Colour::SetAlpha(int alpha) { a = (unsigned char) MID(0,alpha,255); }
void Colour::SetRed(int red) { r = (unsigned char) Mid(0,red,255); }
void Colour::SetGreen(int green) { g = (unsigned char) Mid(0,green,255); }
void Colour::SetBlue(int blue) { b = (unsigned char) Mid(0,blue,255); }
void Colour::SetAlpha(int alpha) { a = (unsigned char) Mid(0,alpha,255); }
//////////////

View file

@ -108,20 +108,29 @@ void FormatHandlerASS::Load(wxInputStream &file,const String encoding)
if (cur[0] == L'[') continue;
// Create and insert line
SectionEntry *entry = MakeEntry(cur,curGroup,version);
SectionEntry *entry = MakeEntry(cur,section,version);
if (entry) section->AddEntry(entry);
}
// Debug
cout << "\nFinished reading file with version=" << version << ".\n\n";
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;
}
///////////////
// Create line
SectionEntry *FormatHandlerASS::MakeEntry(String data,String group,int version)
SectionEntry *FormatHandlerASS::MakeEntry(const String &data,Section *section,int version)
{
// Variables
const String group = section->GetName();
SectionEntry *final = NULL;
// Attachments
@ -143,8 +152,7 @@ SectionEntry *FormatHandlerASS::MakeEntry(String data,String group,int version)
// Format lines
else if (data.Left(7) == _T("Format:")) {
// TODO
//entry = new AssEntry(_T("Format: Layer, Start, End, Style, Name, MarginL, MarginR, MarginV, Effect, Text"));
section->SetProperty(_T("Format"),data.Mid(7).Trim(true).Trim(false));
}
// Garbage
@ -164,8 +172,7 @@ SectionEntry *FormatHandlerASS::MakeEntry(String data,String group,int version)
std::cout << out.mb_str(wxConvUTF8) << std::endl;
}
if (data.Left(7) == _T("Format:")) {
// TODO
//entry = new AssEntry(_T("Format: Name, Fontname, Fontsize, PrimaryColour, SecondaryColour, OutlineColour, BackColour, Bold, Italic, Underline, StrikeOut, ScaleX, ScaleY, Spacing, Angle, BorderStyle, Outline, Shadow, Alignment, MarginL, MarginR, MarginV, Encoding"));
section->SetProperty(_T("Format"),data.Mid(7).Trim(true).Trim(false));
}
}
@ -174,7 +181,15 @@ SectionEntry *FormatHandlerASS::MakeEntry(String data,String group,int version)
// Discard comments
if (data.Left(1) == _T(";")) return NULL;
// TODO
// Parse property
size_t pos = data.Find(_T(':'));
if (pos == wxNOT_FOUND) return NULL;
wxString key = data.Left(pos).Trim(true).Trim(false);
wxString value = data.Mid(pos+1).Trim(true).Trim(false);
// Insert property
section->SetProperty(key,value);
return NULL;
}
// Return entry

View file

@ -48,7 +48,7 @@ namespace Aegilib {
// Advanced Substation Alpha format handler
class FormatHandlerASS : public FormatHandler {
private:
SectionEntry *MakeEntry(String data,String group,int version);
SectionEntry *MakeEntry(const String &data,Section *section,int version);
void ProcessGroup(String cur,String &curGroup,int &version);
Model &model;

View file

@ -35,6 +35,7 @@
#include "format_ass.h"
#include "tokenizer.h"
#include "utils.h"
using namespace Aegilib;
@ -90,9 +91,7 @@ bool DialogueASS::Parse(wxString rawData, int version)
// Not SSA, so read layer number
else {
if (version == 0) version = 1; // Only do it for SSA, not ASS2
long templ;
temp.ToLong(&templ);
layer = templ;
layer = StringToInt(temp);
}
// Get times
@ -105,29 +104,25 @@ bool DialogueASS::Parse(wxString rawData, int version)
// Get margins
for (int i=0;i<3;i++) margin[i] = tkn.GetInt();
margin[3] = margin[2];
// Read next string, which is either bottom margin or effect
temp = tkn.GetString(true);
// Get bottom margin
if (version == 1) margin[3] = margin[2];
bool rollBack = false;
if (version == 2) {
wxString oldTemp = temp;
temp = tkn.GetString().Trim(false).Trim(true);
if (!temp.IsNumber()) {
version = 1;
rollBack = true;
}
else {
long templ;
temp.ToLong(&templ);
margin[3] = templ;
if (temp.IsNumber()) {
// Got margin
margin[3] = StringToInt(temp);
// Read effect
temp = tkn.GetString(true);
}
else version = 1;
}
// Get effect
if (!rollBack) temp = tkn.GetString();
effect = temp;
effect.Trim(true);
effect.Trim(false);
// Get text
text = rawData.Mid(pos+tkn.GetPosition());

View file

@ -59,3 +59,58 @@ void Section::AddEntry(SectionEntry *entry)
{
entries.push_back(entry);
}
//////////////////
// Set a property
void Section::SetProperty(const String &key,const String &value)
{
properties[key] = value;
}
//////////////////////
// Removes a property
void Section::UnsetProperty(const String &key)
{
std::map<String,String>::iterator iter = properties.find(key);
if (iter != properties.end()) properties.erase(iter);
}
//////////////////////////
// Get a property's value
String Section::GetProperty(const String &key) const
{
std::map<String,String>::const_iterator iter = properties.find(key);
if (iter != properties.end()) return iter->second;
else return L"";
}
///////////////////////////////
// Checks if it has a property
bool Section::HasProperty(const String &key) const
{
return properties.find(key) != properties.end();
}
//////////////////////
// Get property count
size_t Section::PropertyCount() const
{
return properties.size();
}
///////////////////////////////////
// Get name of a property by index
String Section::GetPropertyName(size_t index) const
{
std::map<String,String>::const_iterator iter=properties.begin();
for (size_t i=0 ; iter!=properties.end() ; iter++,i++) {
if (i == index) return iter->first;
}
return L"";
}

View file

@ -42,8 +42,8 @@ using namespace Aegilib;
String Time::GetString(int ms_precision,int h_precision)
{
// Enforce sanity
ms_precision = MID(0,ms_precision,3);
h_precision = MID(0,h_precision,2);
ms_precision = Mid(0,ms_precision,3);
h_precision = Mid(0,h_precision,2);
// Generate values
int _ms = ms;

49
aegilib/src/utils.cpp Normal file
View file

@ -0,0 +1,49 @@
// 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 "utils.h"
using namespace Aegilib;
//////////////////////////////////
// Convert a string to an integer
int Aegilib::StringToInt(const String &str)
{
if (!str.IsNumber()) return 0;
long temp;
str.ToLong(&temp);
return (int) temp;
}