From d70d4407e792ac3592da3936990ffbe6134b4abc Mon Sep 17 00:00:00 2001 From: Rodrigo Braz Monteiro Date: Thu, 13 Mar 2008 00:51:31 +0000 Subject: [PATCH] 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. --- aegilib/aegilib.vcproj | 8 +++ aegilib/include/aegilib/aegilib.h | 14 +--- aegilib/include/aegilib/section.h | 13 +++- aegilib/include/aegilib/utils.h | 75 +++++++++++++++++++++ aegilib/src/colour.cpp | 8 +-- aegilib/src/formats/format_ass.cpp | 31 ++++++--- aegilib/src/formats/format_ass.h | 2 +- aegilib/src/formats/format_ass_dialogue.cpp | 31 ++++----- aegilib/src/section.cpp | 55 +++++++++++++++ aegilib/src/time.cpp | 4 +- aegilib/src/utils.cpp | 49 ++++++++++++++ 11 files changed, 242 insertions(+), 48 deletions(-) create mode 100644 aegilib/include/aegilib/utils.h create mode 100644 aegilib/src/utils.cpp diff --git a/aegilib/aegilib.vcproj b/aegilib/aegilib.vcproj index b526eca75..c62dd0d9b 100644 --- a/aegilib/aegilib.vcproj +++ b/aegilib/aegilib.vcproj @@ -227,6 +227,10 @@ RelativePath=".\include\aegilib\tokenizer.h" > + + @@ -324,6 +328,10 @@ RelativePath=".\src\tokenizer.cpp" > + + (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 \ No newline at end of file +#include "utils.h" diff --git a/aegilib/include/aegilib/section.h b/aegilib/include/aegilib/section.h index 128b7b808..60adaf006 100644 --- a/aegilib/include/aegilib/section.h +++ b/aegilib/include/aegilib/section.h @@ -37,6 +37,7 @@ #include "aegistring.h" #include "section_entry.h" #include +#include namespace Aegilib { @@ -44,14 +45,22 @@ namespace Aegilib { class Section { private: std::list entries; + std::map 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); }; diff --git a/aegilib/include/aegilib/utils.h b/aegilib/include/aegilib/utils.h new file mode 100644 index 000000000..9743b0d53 --- /dev/null +++ b/aegilib/include/aegilib/utils.h @@ -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 +T Max(T a,T b) +{ + if (b < a) return a; + return b; +} + +// Returns the smallest of two values +template +T Min(T a,T b) +{ + if (a < b) return a; + return b; +} + +// Returns b, but limiting it to the interval [a,c] +template +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); + +}; diff --git a/aegilib/src/colour.cpp b/aegilib/src/colour.cpp index e916222a6..640e1db60 100644 --- a/aegilib/src/colour.cpp +++ b/aegilib/src/colour.cpp @@ -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); } ////////////// diff --git a/aegilib/src/formats/format_ass.cpp b/aegilib/src/formats/format_ass.cpp index ff3605b54..05bda504f 100644 --- a/aegilib/src/formats/format_ass.cpp +++ b/aegilib/src/formats/format_ass.cpp @@ -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;iGetPropertyName(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 diff --git a/aegilib/src/formats/format_ass.h b/aegilib/src/formats/format_ass.h index a27ad0939..09e98e9fe 100644 --- a/aegilib/src/formats/format_ass.h +++ b/aegilib/src/formats/format_ass.h @@ -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; diff --git a/aegilib/src/formats/format_ass_dialogue.cpp b/aegilib/src/formats/format_ass_dialogue.cpp index c07f80321..476ec2519 100644 --- a/aegilib/src/formats/format_ass_dialogue.cpp +++ b/aegilib/src/formats/format_ass_dialogue.cpp @@ -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()); diff --git a/aegilib/src/section.cpp b/aegilib/src/section.cpp index eda6f86fb..1e1655733 100644 --- a/aegilib/src/section.cpp +++ b/aegilib/src/section.cpp @@ -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::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::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::const_iterator iter=properties.begin(); + for (size_t i=0 ; iter!=properties.end() ; iter++,i++) { + if (i == index) return iter->first; + } + return L""; +} diff --git a/aegilib/src/time.cpp b/aegilib/src/time.cpp index 7cb0c3f4a..53bb59ec5 100644 --- a/aegilib/src/time.cpp +++ b/aegilib/src/time.cpp @@ -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; diff --git a/aegilib/src/utils.cpp b/aegilib/src/utils.cpp new file mode 100644 index 000000000..e6838508b --- /dev/null +++ b/aegilib/src/utils.cpp @@ -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; +}