// 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(); } } }