blob: 560e8a5dc38d73c9b6628ad27eba010e1099ec1f [file] [log] [blame]
Alexander Afanasyevc169a812014-05-20 20:37:29 -04001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
Yingdi Yu5e974202014-01-29 16:59:06 -08002/**
Qiuhan Ding699725d2015-05-24 01:41:09 -07003 * Copyright (c) 2013-2015 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.
Yingdi Yu5e974202014-01-29 16:59:06 -080020 */
21
Yingdi Yu5e974202014-01-29 16:59:06 -080022#include "regex-top-matcher.hpp"
23
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080024#include "regex-backref-manager.hpp"
25#include "regex-pattern-list-matcher.hpp"
Yingdi Yu5e974202014-01-29 16:59:06 -080026
Alexander Afanasyev258ec2b2014-05-14 16:15:37 -070027#include <boost/lexical_cast.hpp>
28
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080029namespace ndn {
Yingdi Yu5e974202014-01-29 16:59:06 -080030
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080031RegexTopMatcher::RegexTopMatcher(const std::string& expr, const std::string& expand)
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070032 : RegexMatcher(expr, EXPR_TOP)
33 , m_expand(expand)
34 , m_isSecondaryUsed(false)
Yingdi Yu5e974202014-01-29 16:59:06 -080035{
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070036 m_primaryBackrefManager = make_shared<RegexBackrefManager>();
37 m_secondaryBackrefManager = make_shared<RegexBackrefManager>();
Yingdi Yu5e974202014-01-29 16:59:06 -080038 compile();
Yingdi Yu5e974202014-01-29 16:59:06 -080039}
40
41RegexTopMatcher::~RegexTopMatcher()
42{
Yingdi Yu5e974202014-01-29 16:59:06 -080043}
44
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070045void
Yingdi Yu5e974202014-01-29 16:59:06 -080046RegexTopMatcher::compile()
47{
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -080048 std::string expr = m_expr;
Yingdi Yu5e974202014-01-29 16:59:06 -080049
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070050 if ('$' != expr[expr.size() - 1])
Yingdi Yu5e974202014-01-29 16:59:06 -080051 expr = expr + "<.*>*";
52 else
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070053 expr = expr.substr(0, expr.size() - 1);
Yingdi Yu5e974202014-01-29 16:59:06 -080054
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070055 if ('^' != expr[0]) {
56 m_secondaryMatcher = make_shared<RegexPatternListMatcher>(
57 "<.*>*" + expr,
Alexander Afanasyevf73f0632014-05-12 18:02:37 -070058 m_secondaryBackrefManager);
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070059 }
60 else {
61 expr = expr.substr(1, expr.size() - 1);
62 }
Yingdi Yu5e974202014-01-29 16:59:06 -080063
Alexander Afanasyevf73f0632014-05-12 18:02:37 -070064 // On OSX 10.9, boost, and C++03 the following doesn't work without ndn::
65 // because the argument-dependent lookup prefers STL to boost
66 m_primaryMatcher = ndn::make_shared<RegexPatternListMatcher>(expr,
67 m_primaryBackrefManager);
Yingdi Yu5e974202014-01-29 16:59:06 -080068}
69
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070070bool
71RegexTopMatcher::match(const Name& name)
Yingdi Yu5e974202014-01-29 16:59:06 -080072{
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070073 m_isSecondaryUsed = false;
Yingdi Yu5e974202014-01-29 16:59:06 -080074
75 m_matchResult.clear();
76
Qiuhan Ding699725d2015-05-24 01:41:09 -070077 if (m_primaryMatcher->match(name, 0, name.size())) {
78 m_matchResult = m_primaryMatcher->getMatchResult();
79 return true;
80 }
81 else {
82 if (static_cast<bool>(m_secondaryMatcher) && m_secondaryMatcher->match(name, 0, name.size())) {
83 m_matchResult = m_secondaryMatcher->getMatchResult();
84 m_isSecondaryUsed = true;
Yingdi Yu5e974202014-01-29 16:59:06 -080085 return true;
86 }
Qiuhan Ding699725d2015-05-24 01:41:09 -070087 return false;
88 }
Yingdi Yu5e974202014-01-29 16:59:06 -080089}
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070090
91bool
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070092RegexTopMatcher::match(const Name& name, size_t, size_t)
Yingdi Yu5e974202014-01-29 16:59:06 -080093{
94 return match(name);
95}
96
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -070097Name
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -070098RegexTopMatcher::expand(const std::string& expandStr)
Yingdi Yu5e974202014-01-29 16:59:06 -080099{
Yingdi Yu5e974202014-01-29 16:59:06 -0800100 Name result;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700101
Qiuhan Ding699725d2015-05-24 01:41:09 -0700102 auto backrefManager =
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700103 (m_isSecondaryUsed ? m_secondaryBackrefManager : m_primaryBackrefManager);
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700104
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700105 size_t backrefNo = backrefManager->size();
Yingdi Yu5e974202014-01-29 16:59:06 -0800106
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800107 std::string expand;
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700108
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700109 if (!expandStr.empty())
Yingdi Yu5e974202014-01-29 16:59:06 -0800110 expand = expandStr;
111 else
112 expand = m_expand;
113
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700114 size_t offset = 0;
Qiuhan Ding699725d2015-05-24 01:41:09 -0700115 while (offset < expand.size()) {
116 std::string item = getItemFromExpand(expand, offset);
117 if (item[0] == '<') {
118 result.append(item.substr(1, item.size() - 2));
Yingdi Yu5e974202014-01-29 16:59:06 -0800119 }
Qiuhan Ding699725d2015-05-24 01:41:09 -0700120 if (item[0] == '\\') {
121 size_t index = boost::lexical_cast<size_t>(item.substr(1, item.size() - 1));
122
123 if (0 == index) {
124 std::vector<name::Component>::iterator it = m_matchResult.begin();
125 std::vector<name::Component>::iterator end = m_matchResult.end();
126 for (; it != end; it++)
127 result.append(*it);
128 }
129 else if (index <= backrefNo) {
130 std::vector<name::Component>::const_iterator it =
131 backrefManager->getBackref(index - 1)->getMatchResult().begin();
132 std::vector<name::Component>::const_iterator end =
133 backrefManager->getBackref(index - 1)->getMatchResult().end();
134 for (; it != end; it++)
135 result.append(*it);
136 }
137 else
138 throw Error("Exceed the range of back reference");
139 }
140 }
Yingdi Yu5e974202014-01-29 16:59:06 -0800141 return result;
142}
143
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800144std::string
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700145RegexTopMatcher::getItemFromExpand(const std::string& expand, size_t& offset)
Yingdi Yu5e974202014-01-29 16:59:06 -0800146{
Alexander Afanasyev1dd95c52014-03-22 19:11:36 -0700147 size_t begin = offset;
Yingdi Yu5e974202014-01-29 16:59:06 -0800148
Qiuhan Ding699725d2015-05-24 01:41:09 -0700149 if (expand[offset] == '\\') {
150 offset++;
151 if (offset >= expand.size())
152 throw Error("wrong format of expand string!");
Yingdi Yu5e974202014-01-29 16:59:06 -0800153
Qiuhan Ding699725d2015-05-24 01:41:09 -0700154 while (expand[offset] <= '9' and expand[offset] >= '0') {
155 offset++;
156 if (offset > expand.size())
157 throw Error("wrong format of expand string!");
Yingdi Yu5e974202014-01-29 16:59:06 -0800158 }
Qiuhan Ding699725d2015-05-24 01:41:09 -0700159 if (offset > begin + 1)
Yingdi Yu5e974202014-01-29 16:59:06 -0800160 return expand.substr(begin, offset - begin);
Qiuhan Ding699725d2015-05-24 01:41:09 -0700161 else
162 throw Error("wrong format of expand string!");
163 }
164 else if (expand[offset] == '<') {
165 offset++;
166 if (offset >= expand.size())
167 throw Error("wrong format of expand string!");
168
169 size_t left = 1;
170 size_t right = 0;
171 while (right < left) {
172 if (expand[offset] == '<')
173 left++;
174 if (expand[offset] == '>')
175 right++;
176 offset++;
177 if (offset >= expand.size())
178 throw Error("wrong format of expand string!");
Yingdi Yu5e974202014-01-29 16:59:06 -0800179 }
Qiuhan Ding699725d2015-05-24 01:41:09 -0700180 return expand.substr(begin, offset - begin);
181 }
Yingdi Yu5e974202014-01-29 16:59:06 -0800182 else
Qiuhan Ding699725d2015-05-24 01:41:09 -0700183 throw Error("wrong format of expand string!");
Yingdi Yu5e974202014-01-29 16:59:06 -0800184}
185
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800186shared_ptr<RegexTopMatcher>
Yingdi Yu5e974202014-01-29 16:59:06 -0800187RegexTopMatcher::fromName(const Name& name, bool hasAnchor)
188{
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800189 std::string regexStr("^");
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700190
Qiuhan Ding699725d2015-05-24 01:41:09 -0700191 for (const auto& comp : name) {
192 regexStr.append("<");
193 regexStr.append(convertSpecialChar(comp.toUri()));
194 regexStr.append(">");
195 }
Yingdi Yu5e974202014-01-29 16:59:06 -0800196
Alexander Afanasyevfdbfc6d2014-04-14 15:12:11 -0700197 if (hasAnchor)
Yingdi Yu5e974202014-01-29 16:59:06 -0800198 regexStr.append("$");
199
Alexander Afanasyevf73f0632014-05-12 18:02:37 -0700200 // On OSX 10.9, boost, and C++03 the following doesn't work without ndn::
201 // because the argument-dependent lookup prefers STL to boost
202 return ndn::make_shared<RegexTopMatcher>(regexStr);
Yingdi Yu5e974202014-01-29 16:59:06 -0800203}
204
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800205std::string
206RegexTopMatcher::convertSpecialChar(const std::string& str)
Yingdi Yu5e974202014-01-29 16:59:06 -0800207{
Alexander Afanasyev36b84cf2014-02-17 19:34:18 -0800208 std::string newStr;
Qiuhan Ding699725d2015-05-24 01:41:09 -0700209 for (size_t i = 0; i < str.size(); i++) {
210 char c = str[i];
211 switch (c)
212 {
213 case '.':
214 case '[':
215 case '{':
216 case '}':
217 case '(':
218 case ')':
219 case '\\':
220 case '*':
221 case '+':
222 case '?':
223 case '|':
224 case '^':
225 case '$':
226 newStr.push_back('\\');
227 // Fallthrough
228 default:
229 newStr.push_back(c);
230 break;
231 }
232 }
Yingdi Yu5e974202014-01-29 16:59:06 -0800233
234 return newStr;
235}
236
Alexander Afanasyevb6b21b32014-04-28 22:38:03 -0700237} // namespace ndn