From 6bafd923f306e3e8a2a2787206955ac6dd9f9eca Mon Sep 17 00:00:00 2001 From: King_DuckZ Date: Sat, 12 Sep 2020 01:32:08 +0100 Subject: [PATCH] Import mime_split from tawashi (kamokan) --- src/meson.build | 1 + src/oro/private/mime_split.cpp | 225 +++++++++++++++++++++++++++++++++ src/oro/private/mime_split.hpp | 35 +++++ 3 files changed, 261 insertions(+) create mode 100644 src/oro/private/mime_split.cpp create mode 100644 src/oro/private/mime_split.hpp diff --git a/src/meson.build b/src/meson.build index 42ba9c9..5b86ae8 100644 --- a/src/meson.build +++ b/src/meson.build @@ -113,6 +113,7 @@ executable(meson.project_name(), 'ini_file.cpp', 'oro/datatypes.cpp', 'oro/private/dateconv.cpp', + 'oro/private/mime_split.cpp', 'oro/items.cpp', 'oro/shops.cpp', 'evloop.cpp', diff --git a/src/oro/private/mime_split.cpp b/src/oro/private/mime_split.cpp new file mode 100644 index 0000000..82865be --- /dev/null +++ b/src/oro/private/mime_split.cpp @@ -0,0 +1,225 @@ +/* Copyright 2017, Michele Santullo + * This file is part of "tawashi". + * + * "tawashi" is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * "tawashi" is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with "tawashi". If not, see . + */ + +#include "mime_split.hpp" +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include + +// The Internet Media Type [9 <#ref-9>] of the attached entity. The syntax is +// the same as the HTTP Content-Type header. +// +// CONTENT_TYPE = "" | media-type +// media-type = type "/" subtype *( ";" parameter) +// type = token +// subtype = token +// parameter = attribute "=" value +// attribute = token +// value = token | quoted-string +// +// The type, subtype and parameter attribute names are not +// case-sensitive. Parameter values may be case sensitive. Media +// types and their use in HTTP are described section 3.6 <#section-3.6> of the +// HTTP/1.0 specification [3 <#ref-3>]. Example: +// +// application/x-www-form-urlencoded +// +// There is no default value for this variable. If and only if it is +// unset, then the script may attempt to determine the media type +// from the data received. If the type remains unknown, then +// application/octet-stream should be assumed. + +BOOST_FUSION_ADAPT_STRUCT( + tawashi::SplitMime, + (boost::string_view, type) + (boost::string_view, subtype) + (tawashi::MimeParametersMapType, parameters) +); + +namespace tawashi { + namespace { + template + struct MimeGrammar : boost::spirit::qi::grammar { + explicit MimeGrammar (const std::string* parString); + + boost::spirit::qi::rule content_type; + boost::spirit::qi::rule media_type; + boost::spirit::qi::rule type; + boost::spirit::qi::rule subtype; + boost::spirit::qi::rule parameter; + boost::spirit::qi::rule attribute; + boost::spirit::qi::rule value; + boost::spirit::qi::rule quoted_string; + boost::spirit::qi::rule token; + const std::string* m_master_string; + Iterator m_begin; + }; + + template + MimeGrammar::MimeGrammar (const std::string* parString) : + MimeGrammar::base_type(content_type), + m_master_string(parString), + m_begin(m_master_string->cbegin()) + { + namespace px = boost::phoenix; + using boost::spirit::ascii::space; + using boost::spirit::qi::char_; + using boost::spirit::qi::lit; + using boost::spirit::qi::alnum; + using boost::spirit::qi::raw; + using boost::spirit::qi::_val; + using boost::spirit::qi::lexeme; + using boost::string_view; + using boost::spirit::_1; + + content_type = -media_type; + media_type = type >> "/" >> subtype >> *(lit(";") >> parameter); + type = token.alias(); + subtype = token.alias(); + parameter = attribute >> "=" >> value; + attribute = token.alias(); + value = token | quoted_string; + + token = raw[+(alnum | char_("_.-"))][ + _val = px::bind( + &string_view::substr, px::construct(px::ref(*m_master_string)), + px::begin(_1) - px::ref(m_begin), + px::size(_1) + ) + ]; + quoted_string = raw[ + lexeme[ + lit('"') >> + *(char_ - '"') >> + '"' + ] + ][_val = px::bind( + &string_view::substr, px::construct(px::ref(*m_master_string)), + px::begin(_1) + 1 - px::ref(m_begin), + px::size(_1) - 2 + )]; + } + + struct simple_token_checker { + typedef bool result_type; + + template + bool operator() (const V& parIn) const { + return std::find(std::begin(parIn), std::end(parIn), ' ') == std::end(parIn) and + std::find(std::begin(parIn), std::end(parIn), '\t') == std::end(parIn); + } + }; + } //unnamed namespace + + SplitMime string_to_mime (const std::string* parMime, bool& parParseOk, int& parParsedCharCount) { + using boost::spirit::qi::blank; + using boost::spirit::qi::blank_type; + + MimeGrammar gramm(parMime); + SplitMime result; + + parParseOk = false; + parParsedCharCount = 0; + + std::string::const_iterator start_it = parMime->cbegin(); + const bool parse_ok = boost::spirit::qi::phrase_parse( + start_it, + parMime->cend(), + gramm, + blank, + result + ); + + parParseOk = parse_ok and (parMime->cend() == start_it); + parParsedCharCount = std::distance(parMime->cbegin(), start_it); + assert(parParsedCharCount >= 0); + return result; + } + + std::string mime_to_string (const SplitMime& parMime, bool& parWriteOk) { + namespace px = boost::phoenix; + using boost::string_view; + using boost::spirit::karma::generate; + using boost::spirit::karma::char_; + using boost::spirit::karma::string; + using boost::spirit::karma::rule; + using boost::spirit::karma::alnum; + using boost::spirit::karma::eps; + using boost::spirit::_val; + + if (parMime.type.empty() or parMime.subtype.empty()) { + parWriteOk = false; + return std::string(); + } + + px::function is_simple_token; + std::string retval; + std::back_insert_iterator out_iter(retval); + rule, string_view()> token; + rule, string_view()> quoted_string; + rule, string_view()> param_value; + + token %= eps(is_simple_token(_val)) << *(alnum | char_("._-")); + quoted_string %= '"' << string << '"'; + param_value %= token | quoted_string; + + parWriteOk = generate( + out_iter, + string << "/" << string << *( + "; " << string << "=" << param_value + ), + parMime + ); + return retval; + } +} //namespace tawashi diff --git a/src/oro/private/mime_split.hpp b/src/oro/private/mime_split.hpp new file mode 100644 index 0000000..f13e9e2 --- /dev/null +++ b/src/oro/private/mime_split.hpp @@ -0,0 +1,35 @@ +/* Copyright 2017, Michele Santullo + * This file is part of "tawashi". + * + * "tawashi" is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * "tawashi" is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with "tawashi". If not, see . + */ + +#pragma once + +#include +#include +#include + +namespace tawashi { + typedef boost::container::flat_map MimeParametersMapType; + + struct SplitMime { + boost::string_view type; + boost::string_view subtype; + MimeParametersMapType parameters; + }; + + SplitMime string_to_mime (const std::string* parMime, bool& parParseOk, int& parParsedCharCount); + std::string mime_to_string (const SplitMime& parMime, bool& parWriteOk); +} //namespace tawashi