diff --git a/CMakeLists.txt b/CMakeLists.txt index 4f40396..8cffd61 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -18,12 +18,16 @@ set( src/grammar.cpp src/parser.cpp src/writer.cpp + src/matcher.cpp ) set( HEADER_FILES include/sdptransform.hpp include/json.hpp + include/string_view.hpp + include/string_view_lite.hpp + include/matcher.hpp ) add_library(sdptransform STATIC ${SOURCE_FILES} ${HEADER_FILES}) diff --git a/include/matcher.hpp b/include/matcher.hpp new file mode 100644 index 0000000..dc0ac63 --- /dev/null +++ b/include/matcher.hpp @@ -0,0 +1,49 @@ +#pragma once + +#include "string_view.hpp" +#include +#include +#include + +namespace sdptransform +{ + namespace matcher + { + class Interface { + public: + virtual bool doMatch(const std::string& content) const = 0; + using Results=std::vector; + virtual Results getMatches(const std::string& content) const = 0; + }; + using Ptr=std::shared_ptr; + + class Regex final : public Interface { + public: + Regex(std::string&& regex) : regex_(std::move(regex)) {} + Regex(const char* prefix, std::string&& regex) : regex_(std::move(regex)), prefix_(prefix) {} + bool doMatch(const std::string& content) const override; + Results getMatches(const std::string& content) const override; + private: + std::pair getIteratorAfterPrefixMatch(const std::string& content) const; + std::regex regex_; + std::string prefix_={}; + }; + + template + inline std::shared_ptr createRegex(T&&... vals) { + return std::make_shared(std::forward(vals)...); + } + + class WholeMatcher final : public Interface { + public: + bool doMatch(const std::string&) const override { return true; } + Results getMatches(const std::string& content) const override { return {string_view(content)}; } + }; + + inline std::shared_ptr createWholeMatcher() { + return std::make_shared(); + } + + } // namespace matcher + +} // namespace sdptransform diff --git a/include/sdptransform.hpp b/include/sdptransform.hpp index cdf6828..e9f5aa4 100644 --- a/include/sdptransform.hpp +++ b/include/sdptransform.hpp @@ -5,8 +5,8 @@ #include #include #include -#include #include +#include "matcher.hpp" using json = nlohmann::json; @@ -18,7 +18,7 @@ namespace sdptransform { std::string name; std::string push; - std::regex reg; + matcher::Ptr reg; std::vector names; std::vector types; std::string format; diff --git a/include/string_view.hpp b/include/string_view.hpp new file mode 100644 index 0000000..64288be --- /dev/null +++ b/include/string_view.hpp @@ -0,0 +1,27 @@ +#pragma once + +#include + +#if __cplusplus >= 201703L +#include +namespace sdptransform { + using string_view=std::string_view; + inline string_view convertMatchToView(const std::ssub_match& match) + { + #if __cplusplus >= 202002L && __cpp_lib_concepts + return string_view(match.first, match.second); + #else + return string_view(&(*match.first), match.second-match.first); + #endif + } +} +#else +#include +namespace sdptransform { + using string_view=string_view_lite; + inline string_view convertMatchToView(const std::ssub_match& match) + { + return string_view(match.first, match.second); + } +} +#endif diff --git a/include/string_view_lite.hpp b/include/string_view_lite.hpp new file mode 100644 index 0000000..d54c168 --- /dev/null +++ b/include/string_view_lite.hpp @@ -0,0 +1,190 @@ +#pragma once + +#include +#include +#include + +namespace sdptransform +{ + // lite version of string_view for c++14 + class string_view_lite + { + public: + // types + using Traits_type = std::char_traits; + using value_type = char; + using pointer = value_type *; + using const_pointer = const value_type *; + using reference = value_type &; + using const_reference = const value_type &; + using const_iterator = const value_type *; + using iterator = const_iterator; + using const_reverse_iterator = std::reverse_iterator; + using reverse_iterator = const_reverse_iterator; + using size_type = size_t; + using difference_type = ptrdiff_t; + static constexpr size_type npos = size_type(-1); + + constexpr string_view_lite() noexcept {} + constexpr string_view_lite(const string_view_lite &) noexcept = default; + constexpr string_view_lite &operator=(const string_view_lite &) noexcept = default; + string_view_lite(const value_type *str) : data_(str), size_(Traits_type::length(str)) {} + constexpr string_view_lite(std::nullptr_t) = delete; + string_view_lite(const value_type *str, size_type len) : data_(str), size_(len) + { + if (Traits_type::length(str) < size_) + { + throw std::runtime_error("string_view_lite constructor : wrong length"); + } + } + string_view_lite(std::string::const_iterator begin, std::string::const_iterator end) : data_(&(*begin)), size_(end - begin) {} + explicit string_view_lite(const std::string &s) : data_(s.data()), size_(s.size()) {} + + // iterator support + constexpr const_iterator begin() const noexcept { return data_; } + constexpr const_iterator end() const noexcept { return data_ + size_; } + constexpr const_iterator cbegin() const noexcept { return begin(); } + constexpr const_iterator cend() const noexcept { return end(); } + const_reverse_iterator rbegin() const noexcept { return const_reverse_iterator(end()); } + const_reverse_iterator rend() const noexcept { return const_reverse_iterator(begin()); } + const_reverse_iterator crbegin() const noexcept { return rbegin(); } + const_reverse_iterator crend() const noexcept { return rend(); } + + // capacity + constexpr size_type size() const noexcept { return size_; } + constexpr size_type length() const noexcept { return size(); } + constexpr size_type max_size() const noexcept { return npos; } + [[nodiscard]] constexpr bool empty() const noexcept + { + return size() == 0U; + } + + // element access + constexpr const_reference operator[](size_type pos) const { return *(data_ + pos); } + constexpr const_reference at(size_type pos) const + { + if (pos >= size_) + { + throw std::out_of_range("string_view_lite at"); + } + return operator[](pos); + } + constexpr const_reference front() const + { + if (empty()) + { + throw std::out_of_range("string_view_lite front"); + } + return *begin(); + } + constexpr const_reference back() const + { + if (empty()) + { + throw std::out_of_range("string_view_lite back"); + } + return *(end() - 1); + } + constexpr const_pointer data() const noexcept { return data_; } + + // modifiers + constexpr void remove_prefix(size_type n) + { + if (n >= size_) + { + string_view_lite sv; + swap(sv); + } + else + { + data_ += n; + size_ -= n; + } + } + constexpr void remove_suffix(size_type n) + { + if (n >= size_) + { + string_view_lite sv; + swap(sv); + } + else + { + size_ -= n; + } + } + void swap(string_view_lite &s) noexcept + { + std::swap(data_, s.data_); + std::swap(size_, s.size_); + } + + // string operations + + string_view_lite substr(size_type pos = 0, size_type n = npos) const + { + if (pos > size_) + { + throw std::out_of_range("string_view_lite substr"); + } + if (pos == size_) + { + return string_view_lite(); + } + if (n == npos || size_ < (n + pos)) + { + return string_view_lite(data_ + pos, size_ - pos); + } + return string_view_lite(data_ + pos, n); + } + + // searching + constexpr size_type find(string_view_lite s, size_type pos = 0) const noexcept + { + return pos >= size() ? npos : std::search(cbegin() + pos, cend(), s.cbegin(), s.cend(), Traits_type::eq) - cbegin(); + } + constexpr size_type find(value_type c, size_type pos = 0) const noexcept + { + return (empty() || pos >= size()) ? npos : std::find(cbegin() + pos, cend(), c) - cbegin(); + } + + constexpr size_type find_first_of(value_type c, size_type pos = 0) const noexcept + { + return find(c, pos); + } + size_type find_last_of(value_type c, size_type pos = npos) const noexcept + { + return empty() ? npos : std::find(const_reverse_iterator(cbegin() + pos + 1), crend(), c) - crbegin(); + } + constexpr size_type find_first_not_of(value_type c, size_type pos = 0) const noexcept + { + return (pos >= size() || empty()) + ? npos + : std::find_if(cbegin() + pos, cend(), [&c](char other) + { return other != c; }) - + cbegin(); + } + constexpr size_type find_last_not_of(value_type c, size_type pos = npos) const noexcept + { + return empty() ? npos : std::find_if(const_reverse_iterator(cbegin() + pos + 1), crend(), [&c](char other) + { return other != c; }) - + crbegin(); + } + + private: + const_pointer data_ = ""; // exposition only + size_type size_ = 0U; // exposition only + }; + + inline std::basic_ostream & + operator<<(std::basic_ostream &os, + string_view_lite str) + { + for (char c : str) + { + os << c; + } + return os; + } + +} // namespace sdptransform diff --git a/src/grammar.cpp b/src/grammar.cpp index c0fb732..419f7a1 100644 --- a/src/grammar.cpp +++ b/src/grammar.cpp @@ -18,7 +18,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(\\d*)$"), + matcher::createRegex("^(\\d*)$"), // names: { }, // types: @@ -39,7 +39,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(\\S*) (\\d*) (\\d*) (\\S*) IP(\\d) (\\S*)"), + matcher::createRegex("^(\\S*) (\\d*) (\\d*) (\\S*) IP(\\d) (\\S*)"), // names: { "username", "sessionId", "sessionVersion", "netType", "ipVer", "address" }, // types: @@ -60,7 +60,7 @@ namespace sdptransform // push: "", // reg: - std::regex("(.*)"), + matcher::createWholeMatcher(), // names: { }, // types: @@ -81,7 +81,7 @@ namespace sdptransform // push: "", // reg: - std::regex("(.*)"), + matcher::createWholeMatcher(), // names: { }, // types: @@ -102,7 +102,7 @@ namespace sdptransform // push: "", // reg: - std::regex("(.*)"), + matcher::createWholeMatcher(), // names: { }, // types: @@ -123,7 +123,7 @@ namespace sdptransform // push: "", // reg: - std::regex("(.*)"), + matcher::createWholeMatcher(), // names: { }, // types: @@ -144,7 +144,7 @@ namespace sdptransform // push: "", // reg: - std::regex("(.*)"), + matcher::createWholeMatcher(), // names: { }, // types: @@ -164,7 +164,7 @@ namespace sdptransform // push: "", // reg: - std::regex("(.*)"), + matcher::createWholeMatcher(), // names: { }, // types: @@ -184,7 +184,7 @@ namespace sdptransform // push: "", // reg: - std::regex("(.*)"), + matcher::createWholeMatcher(), // names: { }, // types: @@ -205,7 +205,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(\\d*) (\\d*)"), + matcher::createRegex("^(\\d*) (\\d*)"), // names: { "start", "stop" }, // types: @@ -226,7 +226,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^IN IP(\\d) ([^\\\\S/]*)(?:/(\\d*))?"), + matcher::createRegex("^IN IP(\\d) ([^\\\\S/]*)(?:/(\\d*))?"), // names: { "version", "ip" , "ttl"}, // types: @@ -254,7 +254,7 @@ namespace sdptransform // push: "bandwidth", // reg: - std::regex("^(TIAS|AS|CT|RR|RS):(\\d*)"), + matcher::createRegex("^(TIAS|AS|CT|RR|RS):(\\d*)"), // names: { "type", "limit" }, // types: @@ -275,7 +275,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(\\w*) (\\d*)(?:/(\\d*))? ([\\w\\/]*)(?: (.*))?"), + matcher::createRegex("^(\\w*) (\\d*)(?:/(\\d*))? ([\\w\\/]*)(?: (.*))?"), // names: { "type", "port", "numPorts", "protocol", "payloads" }, // types: @@ -303,7 +303,7 @@ namespace sdptransform // push: "rtp", // reg: - std::regex("^rtpmap:(\\d*) ([\\w\\-\\.]*)(?:\\s*\\/(\\d*)(?:\\s*\\/(\\S*))?)?"), + matcher::createRegex("rtpmap:", "^(\\d*) ([\\w\\-\\.]*)(?:\\s*\\/(\\d*)(?:\\s*\\/(\\S*))?)?"), // names: { "payload", "codec", "rate", "encoding" }, // types: @@ -329,7 +329,7 @@ namespace sdptransform // push: "fmtp", // reg: - std::regex("^fmtp:(\\d*) (.*)"), + matcher::createRegex("fmtp:", "^(\\d*) (.*)"), // names: { "payload", "config" }, // types: @@ -345,7 +345,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^control:(.*)"), + matcher::createRegex("control:", "^(.*)"), // names: { }, // types: @@ -361,7 +361,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^rtcp:(\\d*)(?: (\\S*) IP(\\d) (\\S*))?"), + matcher::createRegex("rtcp:", "^(\\d*)(?: (\\S*) IP(\\d) (\\S*))?"), // names: { "port", "netType", "ipVer", "address" }, // types: @@ -384,7 +384,7 @@ namespace sdptransform // push: "rtcpFbTrrInt", // reg: - std::regex("^rtcp-fb:(\\*|\\d*) trr-int (\\d*)"), + matcher::createRegex("rtcp-fb:", "^(\\*|\\d*) trr-int (\\d*)"), // names: { "payload", "value" }, // types: @@ -400,7 +400,7 @@ namespace sdptransform // push: "rtcpFb", // reg: - std::regex("^rtcp-fb:(\\*|\\d*) ([\\w\\-_]*)(?: ([\\w\\-_]*))?"), + matcher::createRegex("rtcp-fb:", "^(\\*|\\d*) ([\\w\\-_]*)(?: ([\\w\\-_]*))?"), // names: { "payload", "type", "subtype" }, // types: @@ -425,7 +425,7 @@ namespace sdptransform // push: "ext", // reg: - std::regex("^extmap:(\\d+)(?:\\/(\\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\\S*)(?: (\\S*))?"), + matcher::createRegex("extmap:", "^(\\d+)(?:\\/(\\w+))?(?: (urn:ietf:params:rtp-hdrext:encrypt))? (\\S*)(?: (\\S*))?"), // names: { "value", "direction", "encrypt-uri", "uri", "config" }, // types: @@ -450,7 +450,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(extmap-allow-mixed)"), + matcher::createRegex("^(extmap-allow-mixed)"), // names: { }, // types: @@ -466,7 +466,7 @@ namespace sdptransform // push: "crypto", // reg: - std::regex("^crypto:(\\d*) ([\\w_]*) (\\S*)(?: (\\S*))?"), + matcher::createRegex("crypto:", "^(\\d*) ([\\w_]*) (\\S*)(?: (\\S*))?"), // names: { "id", "suite", "config", "sessionConfig" }, // types: @@ -489,7 +489,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^setup:(\\w*)"), + matcher::createRegex("setup:", "^(\\w*)"), // names: { }, // types: @@ -505,7 +505,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^mid:([^\\s]*)"), + matcher::createRegex("mid:", "^([^\\s]*)"), // names: { }, // types: @@ -521,7 +521,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^msid:(.*)"), + matcher::createRegex("msid:", "^(.*)"), // names: { }, // types: @@ -537,7 +537,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^ptime:(\\d*)"), + matcher::createRegex("ptime:", "^(\\d*)"), // names: { }, // types: @@ -553,7 +553,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^maxptime:(\\d*)"), + matcher::createRegex("maxptime:", "^(\\d*)"), // names: { }, // types: @@ -569,7 +569,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(sendrecv|recvonly|sendonly|inactive)"), + matcher::createRegex("^(sendrecv|recvonly|sendonly|inactive)"), // names: { }, // types: @@ -585,7 +585,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(ice-lite)"), + matcher::createRegex("^(ice-lite)"), // names: { }, // types: @@ -601,7 +601,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^ice-ufrag:(\\S*)"), + matcher::createRegex("ice-ufrag:", "^(\\S*)"), // names: { }, // types: @@ -617,7 +617,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^ice-pwd:(\\S*)"), + matcher::createRegex("ice-pwd:", "^(\\S*)"), // names: { }, // types: @@ -633,7 +633,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^fingerprint:(\\S*) (\\S*)"), + matcher::createRegex("fingerprint:", "^(\\S*) (\\S*)"), // names: { "type", "hash" }, // types: @@ -653,7 +653,7 @@ namespace sdptransform // push: "candidates", // reg: - std::regex("^candidate:(\\S*) (\\d*) (\\S*) (\\d*) (\\S*) (\\d*) typ (\\S*)(?: raddr (\\S*) rport (\\d*))?(?: tcptype (\\S*))?(?: generation (\\d*))?(?: network-id (\\d*))?(?: network-cost (\\d*))?"), + matcher::createRegex("candidate:", "^(\\S*) (\\d*) (\\S*) (\\d*) (\\S*) (\\d*) typ (\\S*)(?: raddr (\\S*) rport (\\d*))?(?: tcptype (\\S*))?(?: generation (\\d*))?(?: network-id (\\d*))?(?: network-cost (\\d*))?"), // names: { "foundation", "component", "transport", "priority", "ip", "port", "type", "raddr", "rport", "tcptype", "generation", "network-id", "network-cost" }, // types: @@ -688,7 +688,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(end-of-candidates)"), + matcher::createRegex("^(end-of-candidates)"), // names: { }, // types: @@ -704,7 +704,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^remote-candidates:(.*)"), + matcher::createRegex("remote-candidates:", "^(.*)"), // names: { }, // types: @@ -720,7 +720,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^ice-options:(\\S*)"), + matcher::createRegex("ice-options:", "^(\\S*)"), // names: { }, // types: @@ -736,7 +736,7 @@ namespace sdptransform // push: "ssrcs", // reg: - std::regex("^ssrc:(\\d*) ([\\w_-]*)(?::(.*))?"), + matcher::createRegex("ssrc:", "^(\\d*) ([\\w_-]*)(?::(.*))?"), // names: { "id", "attribute", "value" }, // types: @@ -768,7 +768,7 @@ namespace sdptransform // push: "ssrcGroups", // reg: - std::regex("^ssrc-group:([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\\w]*) (.*)"), + matcher::createRegex("ssrc-group:", "^([\x21\x23\x24\x25\x26\x27\x2A\x2B\x2D\x2E\\w]*) (.*)"), // names: { "semantics", "ssrcs" }, // types: @@ -784,7 +784,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^msid-semantic:\\s?(\\w*) (\\S*)"), + matcher::createRegex("msid-semantic:", "^\\s?(\\w*) (\\S*)"), // names: { "semantic", "token" }, // types: @@ -800,7 +800,7 @@ namespace sdptransform // push: "groups", // reg: - std::regex("^group:(\\w*) (.*)"), + matcher::createRegex("group:", "^(\\w*) (.*)"), // names: { "type", "mids" }, // types: @@ -816,7 +816,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(rtcp-mux)"), + matcher::createRegex("^(rtcp-mux)"), // names: { }, // types: @@ -832,7 +832,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^(rtcp-rsize)"), + matcher::createRegex("^(rtcp-rsize)"), // names: { }, // types: @@ -848,7 +848,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^sctpmap:(\\d+) (\\S*)(?: (\\d*))?"), + matcher::createRegex("sctpmap:", "^(\\d+) (\\S*)(?: (\\d*))?"), // names: { "sctpmapNumber", "app", "maxMessageSize" }, // types: @@ -871,7 +871,7 @@ namespace sdptransform // push: "", // reg: - std::regex("x-google-flag:([^\\s]*)"), + matcher::createRegex("x-google-flag:([^\\s]*)"), // names: { }, // types: @@ -887,7 +887,7 @@ namespace sdptransform // push: "rids", // reg: - std::regex("^rid:([\\d\\w]+) (\\w+)(?: (.*))?"), + matcher::createRegex("rid:", "^([\\d\\w]+) (\\w+)(?: (.*))?"), // names: { "id", "direction", "params" }, // types: @@ -912,10 +912,10 @@ namespace sdptransform // push: "imageattrs", // reg: - std::regex( + matcher::createRegex("imageattr:", std::string() + // a=imageattr:97 - "^imageattr:(\\d+|\\*)" + + "^(\\d+|\\*)" + // send [x=800,y=640,sar=1.1,q=0.6] [x=480,y=320] // send * "[\\s\\t]+(send|recv)[\\s\\t]+(\\*|\\[\\S+\\](?:[\\s\\t]+\\[\\S+\\])*)" + @@ -945,10 +945,10 @@ namespace sdptransform // push: "", // reg: - std::regex( + matcher::createRegex("simulcast:", std::string() + // a=simulcast: - "^simulcast:" + + "^" + // send 1,2,3;~4,~5 "(send|recv) ([a-zA-Z0-9\\-_~;,]+)" + // space + recv 6;~7,~8 @@ -980,7 +980,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^simulcast: (.+)$"), + matcher::createRegex("simulcast:", "^ (.+)$"), // names: { "value" }, // types: @@ -997,7 +997,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^framerate:(\\d+(?:$|\\.\\d+))"), + matcher::createRegex("framerate:", "^(\\d+(?:$|\\.\\d+))"), // names: { }, // types: @@ -1013,7 +1013,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^source-filter:[\\s\\t]+(excl|incl) (\\S*) (IP4|IP6|\\*) (\\S*) (.*)"), + matcher::createRegex("source-filter:", "^[\\s\\t]+(excl|incl) (\\S*) (IP4|IP6|\\*) (\\S*) (.*)"), // names: { "filterMode", "netType", "addressTypes", "destAddress", "srcList" }, // types: @@ -1029,7 +1029,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^ts-refclk:(.*)"), + matcher::createRegex("ts-refclk:", "^(.*)"), // names: { }, // types: @@ -1045,7 +1045,7 @@ namespace sdptransform // push: "", // reg: - std::regex("^mediaclk:(.*)"), + matcher::createRegex("mediaclk:", "^(.*)"), // names: { }, // types: @@ -1061,7 +1061,7 @@ namespace sdptransform // push: "invalid", // reg: - std::regex("(.*)"), + matcher::createWholeMatcher(), // names: { "value" }, // types: diff --git a/src/matcher.cpp b/src/matcher.cpp new file mode 100644 index 0000000..8f3b9a4 --- /dev/null +++ b/src/matcher.cpp @@ -0,0 +1,42 @@ +#include "matcher.hpp" + +namespace sdptransform +{ + namespace matcher + { + std::pair Regex::getIteratorAfterPrefixMatch(const std::string &content) const + { + auto result = std::make_pair(content.cbegin(), content.cend()); + if (!prefix_.empty()) + { + std::advance(result.first, prefix_.size()); + } + return result; + } + + bool Regex::doMatch(const std::string &content) const + { + if (!prefix_.empty() && content.find(prefix_) != 0U) + { + return false; + } + auto iterators = getIteratorAfterPrefixMatch(content); + return std::regex_search(iterators.first, iterators.second, regex_); + } + + Interface::Results Regex::getMatches(const std::string &content) const + { + auto iterators = getIteratorAfterPrefixMatch(content); + std::smatch matches; + std::regex_search(iterators.first, iterators.second, matches, regex_); + Results results; + for (unsigned i = 1U; i < matches.size(); i++) + { + results.push_back(convertMatchToView(matches[i])); + } + return results; + } + + } // namespace matcher + +} // namespace sdptransform diff --git a/src/parser.cpp b/src/parser.cpp index ff09bc4..38f41ce 100644 --- a/src/parser.cpp +++ b/src/parser.cpp @@ -13,7 +13,7 @@ namespace sdptransform void parseReg(const grammar::Rule& rule, json& location, const std::string& content); void attachProperties( - const std::smatch& match, + const matcher::Interface::Results& match, json& location, const std::vector& names, const std::string& rawName, @@ -34,8 +34,6 @@ namespace sdptransform json parse(const std::string& sdp) { - static const std::regex ValidLineRegex("^([a-z])=(.*)"); - json session = json::object(); std::stringstream sdpstream(sdp); std::string line; @@ -49,7 +47,8 @@ namespace sdptransform line.pop_back(); // Ensure it's a valid SDP line. - if (!std::regex_search(line, ValidLineRegex)) + // we match ^[a-z]= + if (line.size()<2 || line[0]<'a' || line[0] > 'z' || line[1]!='=') continue; char type = line[0]; @@ -79,7 +78,7 @@ namespace sdptransform { auto& rule = rules[j]; - if (std::regex_search(content, rule.reg)) + if (rule.reg->doMatch(content)) { parseReg(rule, *location, content); @@ -220,9 +219,7 @@ namespace sdptransform location[rule.name] = json::object(); } - std::smatch match; - - std::regex_search(content, match, rule.reg); + auto match = rule.reg->getMatches(content); json object = json::object(); json& keyLocation = !rule.push.empty() @@ -240,7 +237,7 @@ namespace sdptransform } void attachProperties( - const std::smatch& match, + const matcher::Interface::Results& match, json& location, const std::vector& names, const std::string& rawName, @@ -249,15 +246,17 @@ namespace sdptransform { if (!rawName.empty() && names.empty()) { - location[rawName] = toType(match[1].str(), types[0]); + const auto& sv = match[0]; + location[rawName] = toType(std::string(sv.data(),sv.size()), types[0]); } else { for (size_t i = 0; i < names.size(); ++i) { - if (i + 1 < match.size() && !match[i + 1].str().empty()) + if (i < match.size() && !match[i].empty()) { - location[names[i]] = toType(match[i + 1].str(), types[i]); + const auto& sv = match[i]; + location[names[i]] = toType(std::string(sv.data(),sv.size()), types[i]); } } } diff --git a/src/writer.cpp b/src/writer.cpp index a510f99..1228ba4 100644 --- a/src/writer.cpp +++ b/src/writer.cpp @@ -2,6 +2,7 @@ #include // size_t #include // std::stringstream #include +#include "string_view.hpp" namespace sdptransform { @@ -115,8 +116,6 @@ namespace sdptransform const json& location ) { - static const std::regex FormatRegex("%[sdv%]"); - const std::string format = rule.format.empty() ? rule.formatFunc( !rule.push.empty() @@ -166,42 +165,54 @@ namespace sdptransform linestream << type << "="; - for( - auto it = std::sregex_iterator(format.begin(), format.end(), FormatRegex); - it != std::sregex_iterator(); - ++it - ) + string_view runningFormat(format); + size_t nextPos = 0U; + for ( + auto pos = runningFormat.find('%'); pos != std::string::npos; pos = runningFormat.find('%', nextPos)) { - const std::smatch& match = *it; - const std::string& str = match.str(); + const char nextChar = (pos + 1 < runningFormat.size()) ? runningFormat[pos + 1] : '0'; + const string_view prefix = runningFormat.substr(0, pos); + + if (nextChar != '%' && nextChar != 'v' && nextChar != 'd' && nextChar != 's') + { + nextPos = pos + 2; + continue; + } if (i >= len) { - linestream << str; + linestream << prefix << '%' << nextChar; } else { - auto& arg = args[i]; + auto &arg = args[i]; i++; - linestream << match.prefix(); + linestream << prefix; - if (str == "%%") + if (nextChar == '%') { linestream << "%"; } - else if (str == "%s" || str == "%d") + else if (nextChar == 's' || nextChar == 'd') { if (arg.is_string()) linestream << arg.get(); else linestream << arg; } - else if (str == "%v") + else if (nextChar == 'v') { // Do nothing. } } + + runningFormat = runningFormat.substr(pos + 2); + nextPos = 0; + } + if (!runningFormat.empty()) + { + linestream << runningFormat; } linestream << "\r\n";