blob: 0fdc54392b4bb8decbb808c8f0394b38dbd327fe [file] [log] [blame]
Davide Pesavento19745dc2017-11-05 19:34:31 -05001/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
2/*
Davide Pesavento90db7ee2018-06-10 11:33:31 -04003 * Copyright (c) 2013-2018 Regents of the University of California.
Davide Pesavento19745dc2017-11-05 19:34:31 -05004 *
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
Davide Pesavento19745dc2017-11-05 19:34:31 -050028#include <cstdlib>
Davide Pesavento90db7ee2018-06-10 11:33:31 -040029#include <regex>
Davide Pesavento19745dc2017-11-05 19:34:31 -050030
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
Davide Pesavento90db7ee2018-06-10 11:33:31 -040094 if (std::regex_match(repeatStruct, std::regex("\\{[0-9]+,[0-9]+\\}"))) {
Davide Pesavento19745dc2017-11-05 19:34:31 -050095 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 }
Davide Pesavento90db7ee2018-06-10 11:33:31 -040099 else if (std::regex_match(repeatStruct, std::regex("\\{,[0-9]+\\}"))) {
Davide Pesavento19745dc2017-11-05 19:34:31 -0500100 size_t separator = repeatStruct.find_first_of(',', 0);
101 min = 0;
102 max = std::atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).data());
103 }
Davide Pesavento90db7ee2018-06-10 11:33:31 -0400104 else if (std::regex_match(repeatStruct, std::regex("\\{[0-9]+,\\}"))) {
Davide Pesavento19745dc2017-11-05 19:34:31 -0500105 size_t separator = repeatStruct.find_first_of(',', 0);
106 min = std::atoi(repeatStruct.substr(1, separator).data());
107 max = MAX_REPETITIONS;
108 }
Davide Pesavento90db7ee2018-06-10 11:33:31 -0400109 else if (std::regex_match(repeatStruct, std::regex("\\{[0-9]+\\}"))) {
Davide Pesavento19745dc2017-11-05 19:34:31 -0500110 min = std::atoi(repeatStruct.substr(1, rsSize - 1).data());
111 max = min;
112 }
113 else
Davide Pesavento90db7ee2018-06-10 11:33:31 -0400114 BOOST_THROW_EXCEPTION(Error("RegexRepeatMatcher::parseRepetition(): Unrecognized format " + m_expr));
Davide Pesavento19745dc2017-11-05 19:34:31 -0500115
116 if (min > MAX_REPETITIONS || max > MAX_REPETITIONS || min > max)
Davide Pesavento90db7ee2018-06-10 11:33:31 -0400117 BOOST_THROW_EXCEPTION(Error("RegexRepeatMatcher::parseRepetition(): Wrong number " + m_expr));
Davide Pesavento19745dc2017-11-05 19:34:31 -0500118
119 m_repeatMin = min;
120 m_repeatMax = max;
121
122 return true;
123 }
124
125 return false;
126}
127
128bool
129RegexRepeatMatcher::match(const Name& name, size_t offset, size_t len)
130{
131 m_matchResult.clear();
132
133 if (m_repeatMin == 0)
134 if (len == 0)
135 return true;
136
137 if (recursiveMatch(0, name, offset, len)) {
138 for (size_t i = offset; i < offset + len; i++)
139 m_matchResult.push_back(name.get(i));
140 return true;
141 }
142
143 return false;
144}
145
146bool
147RegexRepeatMatcher::recursiveMatch(size_t repeat, const Name& name, size_t offset, size_t len)
148{
149 ssize_t tried = len;
150
151 if (0 < len && repeat >= m_repeatMax) {
152 return false;
153 }
154
155 if (0 == len && repeat < m_repeatMin) {
156 return false;
157 }
158
159 if (0 == len && repeat >= m_repeatMin) {
160 return true;
161 }
162
163 auto matcher = m_matchers[0];
164 while (tried >= 0) {
165 if (matcher->match(name, offset, tried) &&
166 recursiveMatch(repeat + 1, name, offset + tried, len - tried))
167 return true;
168 tried--;
169 }
170
171 return false;
172}
173
174} // namespace ndn