diff --git a/aegisub/build/libaegisub_vs2008/libaegisub_vs2008.vcproj b/aegisub/build/libaegisub_vs2008/libaegisub_vs2008.vcproj
index 9d9299f5d..08b5568c1 100644
--- a/aegisub/build/libaegisub_vs2008/libaegisub_vs2008.vcproj
+++ b/aegisub/build/libaegisub_vs2008/libaegisub_vs2008.vcproj
@@ -323,6 +323,14 @@
RelativePath="..\..\libaegisub\common\option_visit.h"
>
+
+
+
+
diff --git a/aegisub/libaegisub/Makefile b/aegisub/libaegisub/Makefile
index 368d293d0..8b57339ae 100644
--- a/aegisub/libaegisub/Makefile
+++ b/aegisub/libaegisub/Makefile
@@ -27,10 +27,11 @@ SRC += \
common/hotkey.cpp \
common/io.cpp \
common/json.cpp \
+ common/keyframe.cpp \
common/mru.cpp \
common/option.cpp \
common/option_visit.cpp \
- common/keyframe.cpp \
+ common/parser.cpp \
common/util.cpp \
common/log.cpp \
common/thesaurus.cpp \
diff --git a/aegisub/libaegisub/common/color.cpp b/aegisub/libaegisub/common/color.cpp
index abc260e47..730e49adc 100644
--- a/aegisub/libaegisub/common/color.cpp
+++ b/aegisub/libaegisub/common/color.cpp
@@ -16,83 +16,10 @@
#include "libaegisub/color.h"
-#include
+#include "parser.h"
+
#include
#include
-#include
-#include
-#include
-#include
-#include
-#include
-#include
-
-BOOST_FUSION_ADAPT_STRUCT(
- agi::Color,
- (unsigned char, r)
- (unsigned char, g)
- (unsigned char, b)
- (unsigned char, a)
-)
-
-namespace {
-using namespace boost::spirit;
-
-struct unpack_colors : public boost::static_visitor {
- template struct result { typedef agi::Color type; };
-
- template agi::Color operator()(T arg) const {
- return boost::apply_visitor(*this, arg);
- }
-
- agi::Color operator()(int abgr) const { return (*this)((unsigned)abgr); }
- agi::Color operator()(unsigned int abgr) const {
- return agi::Color(abgr & 0xFF, (abgr >> 8) & 0xFF, (abgr >> 16) & 0xFF, (abgr >> 24) & 0xFF);
- }
-};
-
-template
-struct color_grammar : qi::grammar {
- qi::rule color;
-
- qi::rule css_color;
- qi::rule ass_color;
-
- qi::rule rgb_component;
- qi::rule rgb_percent;
- qi::rule hex_byte;
- qi::rule hex_char;
-
- qi::rule comma;
- qi::rule blank;
-
-#define HEX_PARSER(type, len) qi::uint_parser()
-
- color_grammar() : color_grammar::base_type(color) {
- color = css_color | ass_color;
-
- boost::phoenix::function unpack;
- ass_color = (
- int_
- | -lit('&') >> -(lit('H') | lit('h')) >> (HEX_PARSER(int, 8) | HEX_PARSER(int, 6)) >> -lit('&')
- )[_val = unpack(_1)] >> blank >> qi::eoi;
-
- css_color
- = "rgb(" >> blank >> rgb_component >> comma >> rgb_component >> comma >> rgb_component >> blank >> ')'
- | '#' >> hex_byte >> hex_byte >> hex_byte
- | '#' >> hex_char >> hex_char >> hex_char
- ;
-
- hex_char = HEX_PARSER(int, 1)[_val = _1 * 16 + _1];
- hex_byte = HEX_PARSER(int, 2);
- rgb_component = qi::uint_parser();
-
- comma = *qi::blank >> "," >> *qi::blank;
- blank = *qi::blank;
- }
-};
-
-}
namespace agi {
@@ -105,14 +32,7 @@ Color::Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a)
Color::Color(std::string const& str)
: r(0), g(0), b(0), a(0)
{
- const char *begin = &str[0];
- parse(begin, &str[str.size()], color_grammar(), *this);
-}
-
-Color::Color(const char *str)
-: r(0), g(0), b(0), a(0)
-{
- parse(str, str + strlen(str), color_grammar(), *this);
+ parser::parse(*this, str);
}
std::string Color::GetAssStyleFormatted() const {
diff --git a/aegisub/libaegisub/common/parser.cpp b/aegisub/libaegisub/common/parser.cpp
new file mode 100644
index 000000000..9d9359cf0
--- /dev/null
+++ b/aegisub/libaegisub/common/parser.cpp
@@ -0,0 +1,108 @@
+// Copyright (c) 2012, Thomas Goyne
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+#include "../config.h"
+
+#include "parser.h"
+
+#include "libaegisub/color.h"
+
+#include
+#include
+#include
+#include
+#include
+
+BOOST_FUSION_ADAPT_STRUCT(
+ agi::Color,
+ (unsigned char, r)
+ (unsigned char, g)
+ (unsigned char, b)
+ (unsigned char, a)
+)
+
+namespace {
+using namespace boost::spirit;
+
+/// Convert a abgr value in an int or unsigned int to an agi::Color
+struct unpack_colors : public boost::static_visitor {
+ template struct result { typedef agi::Color type; };
+
+ template agi::Color operator()(T arg) const {
+ return boost::apply_visitor(*this, arg);
+ }
+
+ agi::Color operator()(int abgr) const { return (*this)((unsigned)abgr); }
+ agi::Color operator()(unsigned int abgr) const {
+ return agi::Color(abgr & 0xFF, (abgr >> 8) & 0xFF, (abgr >> 16) & 0xFF, (abgr >> 24) & 0xFF);
+ }
+};
+
+template
+struct color_grammar : qi::grammar {
+ qi::rule color;
+
+ qi::rule css_color;
+ qi::rule ass_color;
+
+ qi::rule rgb_component;
+ qi::rule rgb_percent;
+ qi::rule hex_byte;
+ qi::rule hex_char;
+
+ qi::rule comma;
+ qi::rule blank;
+
+#define HEX_PARSER(type, len) qi::uint_parser()
+
+ color_grammar() : color_grammar::base_type(color) {
+ color = css_color | ass_color;
+
+ boost::phoenix::function unpack;
+
+ // Order is important here; int_ (for SSA) needs to come before the ASS
+ // option as decimal numbers of the appropriate length are also valid
+ // hex numbers
+ // ASS with alpha needs to come before ASS without alpha for the same
+ // reason
+ ass_color = (
+ int_
+ | -lit('&') >> -(lit('H') | lit('h')) >> (HEX_PARSER(int, 8) | HEX_PARSER(int, 6)) >> -lit('&')
+ )[_val = unpack(_1)] >> blank >> qi::eoi;
+
+ css_color
+ = "rgb(" >> blank >> rgb_component >> comma >> rgb_component >> comma >> rgb_component >> blank >> ')'
+ | '#' >> hex_byte >> hex_byte >> hex_byte
+ | '#' >> hex_char >> hex_char >> hex_char
+ ;
+
+ hex_char = HEX_PARSER(int, 1)[_val = _1 * 16 + _1];
+ hex_byte = HEX_PARSER(int, 2);
+ rgb_component = qi::uint_parser();
+
+ comma = *qi::blank >> "," >> *qi::blank;
+ blank = *qi::blank;
+ }
+};
+
+}
+
+namespace agi { namespace parser {
+ bool parse(Color &dst, std::string const& str) {
+ std::string::const_iterator begin = str.begin();
+ bool parsed = parse(begin, str.end(), color_grammar(), dst);
+ return parsed && begin == str.end();
+ }
+}
+}
diff --git a/aegisub/libaegisub/common/parser.h b/aegisub/libaegisub/common/parser.h
new file mode 100644
index 000000000..f5e07f855
--- /dev/null
+++ b/aegisub/libaegisub/common/parser.h
@@ -0,0 +1,41 @@
+// Copyright (c) 2012, Thomas Goyne
+//
+// Permission to use, copy, modify, and distribute this software for any
+// purpose with or without fee is hereby granted, provided that the above
+// copyright notice and this permission notice appear in all copies.
+//
+// THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+// WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+// MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+// ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+// WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+// ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+// OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+
+#ifndef LAGI_PRE
+#include
+#endif
+
+namespace agi {
+ struct Color;
+
+ namespace parser {
+ /// Try to parse a string as a color
+ /// @param[out] dst Color struct to populate with the parsed result
+ /// @param str String to parse
+ /// @return Was the string successfully parsed as a color?
+ ///
+ /// If this function returns false, the contents of dst is undefined. It
+ /// may contain partially-parsed garbage.
+ ///
+ /// This function supports the following formats:
+ /// * SSA colors (i.e. a decimal number representing a bgr value)
+ /// * ASS override and style formats (a (a)bgr hex number possibly with
+ /// some ampersands and an H somewhere)
+ /// * CSS-style #rrggbb and #rgb
+ /// * CSS-style rgb(r,g,b)
+ ///
+ /// CSS's rgb(r%,g%,b%) format is not currently supported.
+ bool parse(Color &dst, std::string const& str);
+ }
+}
diff --git a/aegisub/libaegisub/include/libaegisub/color.h b/aegisub/libaegisub/include/libaegisub/color.h
index 0f40bc8c5..c6abe6ab0 100644
--- a/aegisub/libaegisub/include/libaegisub/color.h
+++ b/aegisub/libaegisub/include/libaegisub/color.h
@@ -28,7 +28,6 @@ namespace agi {
Color();
Color(unsigned char r, unsigned char g, unsigned char b, unsigned char a = 0);
Color(std::string const& str);
- Color(const char *str);
bool operator==(Color const& col) const;
bool operator!=(Color const& col) const;
diff --git a/aegisub/src/libresrc/default_config.json b/aegisub/src/libresrc/default_config.json
index fb0ba34c4..f0238777b 100644
--- a/aegisub/src/libresrc/default_config.json
+++ b/aegisub/src/libresrc/default_config.json
@@ -413,14 +413,14 @@
"Colour Picker" : {
"Mode" : 4,
"Recent Colours" : [
- "&H000000&",
- "&H0000FF&",
- "&H00FFFF&",
- "&H00FF00&",
- "&HFFFF00&",
- "&HFF0000&",
- "&HFF00FF&",
- "&HFFFFFF&"
+ {"color" : "&H000000&"},
+ {"color" : "&H0000FF&"},
+ {"color" : "&H00FFFF&"},
+ {"color" : "&H00FF00&"},
+ {"color" : "&HFFFF00&"},
+ {"color" : "&HFF0000&"},
+ {"color" : "&HFF00FF&"},
+ {"color" : "&HFFFFFF&"}
],
"Last" : {
"X" : -1,
diff --git a/aegisub/src/libresrc/osx/default_config.json b/aegisub/src/libresrc/osx/default_config.json
index c4c334ce4..70d2bf383 100644
--- a/aegisub/src/libresrc/osx/default_config.json
+++ b/aegisub/src/libresrc/osx/default_config.json
@@ -413,14 +413,14 @@
"Colour Picker" : {
"Mode" : 4,
"Recent Colours" : [
- "&H000000&",
- "&H0000FF&",
- "&H00FFFF&",
- "&H00FF00&",
- "&HFFFF00&",
- "&HFF0000&",
- "&HFF00FF&",
- "&HFFFFFF&"
+ {"color" : "&H000000&"},
+ {"color" : "&H0000FF&"},
+ {"color" : "&H00FFFF&"},
+ {"color" : "&H00FF00&"},
+ {"color" : "&HFFFF00&"},
+ {"color" : "&HFF0000&"},
+ {"color" : "&HFF00FF&"},
+ {"color" : "&HFFFFFF&"}
],
"Last" : {
"X" : -1,
diff --git a/aegisub/tests/libaegisub_color.cpp b/aegisub/tests/libaegisub_color.cpp
index f657c5472..71ed86bb1 100644
--- a/aegisub/tests/libaegisub_color.cpp
+++ b/aegisub/tests/libaegisub_color.cpp
@@ -44,11 +44,11 @@ TEST(lagi_color, hex) {
}
TEST(lagi_color, rgb) {
- EXPECT_EQ(agi::Color(0, 0, 0), "rgb(0, 0, 0)");
- EXPECT_EQ(agi::Color(255, 255, 255), "rgb(255, 255, 255)");
- EXPECT_EQ(agi::Color(255, 255, 255), "rgb(255,255,255)");
- EXPECT_EQ(agi::Color(255, 0, 127), "rgb(255, 0, 127)");
- EXPECT_EQ(agi::Color(16, 32, 48), "rgb( 16 , 32 , 48 )");
+ EXPECT_EQ(agi::Color(0, 0, 0), agi::Color("rgb(0, 0, 0)"));
+ EXPECT_EQ(agi::Color(255, 255, 255), agi::Color("rgb(255, 255, 255)"));
+ EXPECT_EQ(agi::Color(255, 255, 255), agi::Color("rgb(255,255,255)"));
+ EXPECT_EQ(agi::Color(255, 0, 127), agi::Color("rgb(255, 0, 127)"));
+ EXPECT_EQ(agi::Color(16, 32, 48), agi::Color("rgb( 16 , 32 , 48 )"));
EXPECT_EQ("rgb(0, 0, 0)", agi::Color(0, 0, 0).GetRgbFormatted());
EXPECT_EQ("rgb(255, 255, 255)", agi::Color(255, 255, 255).GetRgbFormatted());
diff --git a/aegisub/tests/libaegisub_option.cpp b/aegisub/tests/libaegisub_option.cpp
index 1832e1d63..2a22646d4 100644
--- a/aegisub/tests/libaegisub_option.cpp
+++ b/aegisub/tests/libaegisub_option.cpp
@@ -132,7 +132,7 @@ TEST_F(lagi_option, flush_roundtrip) {
EXPECT_NO_THROW(opt.Get("Integer")->SetInt(1));
EXPECT_NO_THROW(opt.Get("Double")->SetDouble(1.1));
EXPECT_NO_THROW(opt.Get("String")->SetString("hello"));
- EXPECT_NO_THROW(opt.Get("Color")->SetColor("rgb(255,255,255)"));
+ EXPECT_NO_THROW(opt.Get("Color")->SetColor(agi::Color("rgb(255,255,255)")));
EXPECT_NO_THROW(opt.Get("Boolean")->SetBool(true));
std::vector int_arr; int_arr.push_back(1);
@@ -141,7 +141,7 @@ TEST_F(lagi_option, flush_roundtrip) {
EXPECT_NO_THROW(opt.Get("Array/Double")->SetListDouble(double_arr));
std::vector str_arr; str_arr.push_back("hello");
EXPECT_NO_THROW(opt.Get("Array/String")->SetListString(str_arr));
- std::vector clr_arr; clr_arr.push_back("rgb(255,255,255)");
+ std::vector clr_arr; clr_arr.push_back(agi::Color("rgb(255,255,255)"));
EXPECT_NO_THROW(opt.Get("Array/Color")->SetListColor(clr_arr));
std::vector bool_arr; bool_arr.push_back(true);
EXPECT_NO_THROW(opt.Get("Array/Boolean")->SetListBool(bool_arr));