blob: 35149515dbaff9782ff82b0fc3d7e9641b6f2e18 [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Davide Pesavento45ab9a92017-11-05 19:34:31 -05002/*
Davide Pesaventodb4da5e2018-06-15 11:37:52 -04003 * Copyright (c) 2013-2018 Regents of the University of California.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07004 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -07006 *
Alexander Afanasyevc169a812014-05-20 20:37:29 -04007 * ndn-cxx library is free software: you can redistribute it and/or modify it under the
8 * terms of the GNU Lesser General Public License as published by the Free Software
9 * Foundation, either version 3 of the License, or (at your option) any later version.
10 *
11 * ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
12 * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
13 * PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
14 *
15 * You should have received copies of the GNU General Public License and GNU Lesser
16 * General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
17 * <http://www.gnu.org/licenses/>.
18 *
19 * See AUTHORS.md for complete list of ndn-cxx authors and contributors.
Alexander Afanasyevdfa52c42014-04-24 21:10:11 -070020 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
Yingdi Yu5e974202014-01-29 16:59:06 -080022 */
23
Yingdi Yu5e974202014-01-29 16:59:06 -080024#include "regex-top-matcher.hpp"
25
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080026#include "regex-backref-manager.hpp"
27#include "regex-pattern-list-matcher.hpp"
Yingdi Yu5e974202014-01-29 16:59:06 -080028
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070029#include <boost/lexical_cast.hpp>
30
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080031namespace ndn {
Yingdi Yu5e974202014-01-29 16:59:06 -080032
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080033RegexTopMatcher::RegexTopMatcher(const std::string& expr, const std::string& expand)
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070034 : RegexMatcher(expr, EXPR_TOP)
35 , m_expand(expand)
36 , m_isSecondaryUsed(false)
Yingdi Yu5e974202014-01-29 16:59:06 -080037{
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070038 m_primaryBackrefManager = make_shared<RegexBackrefManager>();
39 m_secondaryBackrefManager = make_shared<RegexBackrefManager>();
Yingdi Yu5e974202014-01-29 16:59:06 -080040 compile();
Yingdi Yu5e974202014-01-29 16:59:06 -080041}
42
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070043void
Yingdi Yu5e974202014-01-29 16:59:06 -080044RegexTopMatcher::compile()
45{
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080046 std::string expr = m_expr;
Yingdi Yu5e974202014-01-29 16:59:06 -080047
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070048 if ('$' != expr[expr.size() - 1])
Yingdi Yu5e974202014-01-29 16:59:06 -080049 expr = expr + "<.*>*";
50 else
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070051 expr = expr.substr(0, expr.size() - 1);
Yingdi Yu5e974202014-01-29 16:59:06 -080052
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070053 if ('^' != expr[0]) {
Davide Pesavento45ab9a92017-11-05 19:34:31 -050054 m_secondaryMatcher = make_shared<RegexPatternListMatcher>("<.*>*" + expr,
55 m_secondaryBackrefManager);
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070056 }
57 else {
58 expr = expr.substr(1, expr.size() - 1);
59 }
Yingdi Yu5e974202014-01-29 16:59:06 -080060
Davide Pesavento45ab9a92017-11-05 19:34:31 -050061 m_primaryMatcher = make_shared<RegexPatternListMatcher>(expr, m_primaryBackrefManager);
Yingdi Yu5e974202014-01-29 16:59:06 -080062}
63
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070064bool
65RegexTopMatcher::match(const Name& name)
Yingdi Yu5e974202014-01-29 16:59:06 -080066{
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070067 m_isSecondaryUsed = false;
Yingdi Yu5e974202014-01-29 16:59:06 -080068
69 m_matchResult.clear();
70
Davide Pesavento45ab9a92017-11-05 19:34:31 -050071 if (m_primaryMatcher->match(name, 0, name.size())) {
72 m_matchResult = m_primaryMatcher->getMatchResult();
73 return true;
74 }
75 else {
76 if (m_secondaryMatcher != nullptr && m_secondaryMatcher->match(name, 0, name.size())) {
77 m_matchResult = m_secondaryMatcher->getMatchResult();
78 m_isSecondaryUsed = true;
Yingdi Yu5e974202014-01-29 16:59:06 -080079 return true;
80 }
Davide Pesavento45ab9a92017-11-05 19:34:31 -050081 return false;
82 }
Yingdi Yu5e974202014-01-29 16:59:06 -080083}
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070084
85bool
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070086RegexTopMatcher::match(const Name& name, size_t, size_t)
Yingdi Yu5e974202014-01-29 16:59:06 -080087{
88 return match(name);
89}
90
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070091Name
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070092RegexTopMatcher::expand(const std::string& expandStr)
Yingdi Yu5e974202014-01-29 16:59:06 -080093{
Davide Pesavento45ab9a92017-11-05 19:34:31 -050094 auto backrefManager = m_isSecondaryUsed ? m_secondaryBackrefManager : m_primaryBackrefManager;
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070095 size_t backrefNo = backrefManager->size();
Yingdi Yu5e974202014-01-29 16:59:06 -080096
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080097 std::string expand;
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070098 if (!expandStr.empty())
Yingdi Yu5e974202014-01-29 16:59:06 -080099 expand = expandStr;
100 else
101 expand = m_expand;
102
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500103 Name result;
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700104 size_t offset = 0;
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500105 while (offset < expand.size()) {
106 std::string item = getItemFromExpand(expand, offset);
107 if (item[0] == '<') {
108 result.append(item.substr(1, item.size() - 2));
Yingdi Yu5e974202014-01-29 16:59:06 -0800109 }
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500110 if (item[0] == '\\') {
111 size_t index = boost::lexical_cast<size_t>(item.substr(1, item.size() - 1));
112 if (index == 0) {
113 for (const auto& i : m_matchResult)
114 result.append(i);
115 }
116 else if (index <= backrefNo) {
117 for (const auto& i : backrefManager->getBackref(index - 1)->getMatchResult())
118 result.append(i);
119 }
120 else
121 BOOST_THROW_EXCEPTION(Error("Exceed the range of back reference"));
122 }
123 }
124
Yingdi Yu5e974202014-01-29 16:59:06 -0800125 return result;
126}
127
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800128std::string
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700129RegexTopMatcher::getItemFromExpand(const std::string& expand, size_t& offset)
Yingdi Yu5e974202014-01-29 16:59:06 -0800130{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700131 size_t begin = offset;
Yingdi Yu5e974202014-01-29 16:59:06 -0800132
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500133 if (expand[offset] == '\\') {
134 offset++;
135 if (offset >= expand.size())
136 BOOST_THROW_EXCEPTION(Error("Wrong format of expand string"));
Yingdi Yu5e974202014-01-29 16:59:06 -0800137
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500138 while (expand[offset] <= '9' and expand[offset] >= '0') {
139 offset++;
140 if (offset > expand.size())
141 BOOST_THROW_EXCEPTION(Error("Wrong format of expand string"));
Yingdi Yu5e974202014-01-29 16:59:06 -0800142 }
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500143 if (offset > begin + 1)
Yingdi Yu5e974202014-01-29 16:59:06 -0800144 return expand.substr(begin, offset - begin);
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500145 else
146 BOOST_THROW_EXCEPTION(Error("Wrong format of expand string"));
147 }
148 else if (expand[offset] == '<') {
149 offset++;
150 if (offset >= expand.size())
151 BOOST_THROW_EXCEPTION(Error("Wrong format of expand string"));
152
153 size_t left = 1;
154 size_t right = 0;
155 while (right < left) {
156 if (expand[offset] == '<')
157 left++;
158 if (expand[offset] == '>')
159 right++;
160 offset++;
161 if (offset >= expand.size())
162 BOOST_THROW_EXCEPTION(Error("Wrong format of expand string"));
Yingdi Yu5e974202014-01-29 16:59:06 -0800163 }
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500164 return expand.substr(begin, offset - begin);
165 }
Yingdi Yu5e974202014-01-29 16:59:06 -0800166 else
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500167 BOOST_THROW_EXCEPTION(Error("Wrong format of expand string"));
Yingdi Yu5e974202014-01-29 16:59:06 -0800168}
169
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800170shared_ptr<RegexTopMatcher>
Yingdi Yu5e974202014-01-29 16:59:06 -0800171RegexTopMatcher::fromName(const Name& name, bool hasAnchor)
172{
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800173 std::string regexStr("^");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700174
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400175 for (const auto& i : name) {
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500176 regexStr.append("<");
Davide Pesaventodb4da5e2018-06-15 11:37:52 -0400177 regexStr.append(convertSpecialChar(i.toUri()));
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500178 regexStr.append(">");
179 }
Yingdi Yu5e974202014-01-29 16:59:06 -0800180
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700181 if (hasAnchor)
Yingdi Yu5e974202014-01-29 16:59:06 -0800182 regexStr.append("$");
183
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500184 return make_shared<RegexTopMatcher>(regexStr);
Yingdi Yu5e974202014-01-29 16:59:06 -0800185}
186
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800187std::string
188RegexTopMatcher::convertSpecialChar(const std::string& str)
Yingdi Yu5e974202014-01-29 16:59:06 -0800189{
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800190 std::string newStr;
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500191
192 for (size_t i = 0; i < str.size(); i++) {
193 char c = str[i];
194 switch (c) {
195 case '.':
196 case '[':
197 case '{':
198 case '}':
199 case '(':
200 case ')':
201 case '\\':
202 case '*':
203 case '+':
204 case '?':
205 case '|':
206 case '^':
207 case '$':
208 newStr.push_back('\\');
209 NDN_CXX_FALLTHROUGH;
210 default:
211 newStr.push_back(c);
212 break;
Yingdi Yu5e974202014-01-29 16:59:06 -0800213 }
Davide Pesavento45ab9a92017-11-05 19:34:31 -0500214 }
Yingdi Yu5e974202014-01-29 16:59:06 -0800215
216 return newStr;
217}
218
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700219} // namespace ndn