blob: 17986bf6a5c923fc4d4d5d5885e5fb19463f3487 [file] [log] [blame]
Davide Pesavento19745dc2017-11-05 19:34:31 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
3 * Copyright (c) 2013-2017 Regents of the University of California.
4 *
5 * This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
6 *
7 * 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.
20 *
21 * @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
22 */
23
24#include "regex-repeat-matcher.hpp"
25#include "regex-backref-matcher.hpp"
26#include "regex-component-set-matcher.hpp"
27
28#include <boost/regex.hpp>
29#include <cstdlib>
30
31namespace ndn {
32
33RegexRepeatMatcher::RegexRepeatMatcher(const std::string& expr,
34 shared_ptr<RegexBackrefManager> backrefManager,
35 size_t indicator)
36 : RegexMatcher(expr, EXPR_REPEAT_PATTERN, std::move(backrefManager))
37 , m_indicator(indicator)
38{
39 compile();
40}
41
42void
43RegexRepeatMatcher::compile()
44{
45 if ('(' == m_expr[0]) {
46 auto matcher = make_shared<RegexBackrefMatcher>(m_expr.substr(0, m_indicator), m_backrefManager);
47 m_backrefManager->pushRef(matcher);
48 matcher->lateCompile();
49 m_matchers.push_back(std::move(matcher));
50 }
51 else {
52 m_matchers.push_back(make_shared<RegexComponentSetMatcher>(m_expr.substr(0, m_indicator),
53 m_backrefManager));
54 }
55
56 parseRepetition();
57}
58
59bool
60RegexRepeatMatcher::parseRepetition()
61{
62 size_t exprSize = m_expr.size();
63 const size_t MAX_REPETITIONS = std::numeric_limits<size_t>::max();
64
65 if (exprSize == m_indicator) {
66 m_repeatMin = 1;
67 m_repeatMax = 1;
68 return true;
69 }
70
71 if (exprSize == (m_indicator + 1)) {
72 if ('?' == m_expr[m_indicator]) {
73 m_repeatMin = 0;
74 m_repeatMax = 1;
75 return true;
76 }
77 if ('+' == m_expr[m_indicator]) {
78 m_repeatMin = 1;
79 m_repeatMax = MAX_REPETITIONS;
80 return true;
81 }
82 if ('*' == m_expr[m_indicator]) {
83 m_repeatMin = 0;
84 m_repeatMax = MAX_REPETITIONS;
85 return true;
86 }
87 }
88 else {
89 std::string repeatStruct = m_expr.substr(m_indicator, exprSize - m_indicator);
90 size_t rsSize = repeatStruct.size();
91 size_t min = 0;
92 size_t max = 0;
93
94 if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,[0-9]+\\}"))) {
95 size_t separator = repeatStruct.find_first_of(',', 0);
96 min = std::atoi(repeatStruct.substr(1, separator - 1).data());
97 max = std::atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).data());
98 }
99 else if (boost::regex_match(repeatStruct, boost::regex("\\{,[0-9]+\\}"))) {
100 size_t separator = repeatStruct.find_first_of(',', 0);
101 min = 0;
102 max = std::atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).data());
103 }
104 else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,\\}"))) {
105 size_t separator = repeatStruct.find_first_of(',', 0);
106 min = std::atoi(repeatStruct.substr(1, separator).data());
107 max = MAX_REPETITIONS;
108 }
109 else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+\\}"))) {
110 min = std::atoi(repeatStruct.substr(1, rsSize - 1).data());
111 max = min;
112 }
113 else
114 BOOST_THROW_EXCEPTION(Error(std::string("Error: RegexRepeatMatcher.ParseRepetition():")
115 + " Unrecognized format " + m_expr));
116
117 if (min > MAX_REPETITIONS || max > MAX_REPETITIONS || min > max)
118 BOOST_THROW_EXCEPTION(Error(std::string("Error: RegexRepeatMatcher.ParseRepetition():")
119 + " Wrong number " + m_expr));
120
121 m_repeatMin = min;
122 m_repeatMax = max;
123
124 return true;
125 }
126
127 return false;
128}
129
130bool
131RegexRepeatMatcher::match(const Name& name, size_t offset, size_t len)
132{
133 m_matchResult.clear();
134
135 if (m_repeatMin == 0)
136 if (len == 0)
137 return true;
138
139 if (recursiveMatch(0, name, offset, len)) {
140 for (size_t i = offset; i < offset + len; i++)
141 m_matchResult.push_back(name.get(i));
142 return true;
143 }
144
145 return false;
146}
147
148bool
149RegexRepeatMatcher::recursiveMatch(size_t repeat, const Name& name, size_t offset, size_t len)
150{
151 ssize_t tried = len;
152
153 if (0 < len && repeat >= m_repeatMax) {
154 return false;
155 }
156
157 if (0 == len && repeat < m_repeatMin) {
158 return false;
159 }
160
161 if (0 == len && repeat >= m_repeatMin) {
162 return true;
163 }
164
165 auto matcher = m_matchers[0];
166 while (tried >= 0) {
167 if (matcher->match(name, offset, tried) &&
168 recursiveMatch(repeat + 1, name, offset + tried, len - tried))
169 return true;
170 tried--;
171 }
172
173 return false;
174}
175
176} // namespace ndn