Compare commits
2
Commits
master
...
feature-schema
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
699725dae1 | ||
|
|
b56c54ebc1 |
No files matched your search
@@ -34,6 +34,7 @@ ndn-cxx Documentation
|
||||
+ :doc:`tutorials/security-validator-config`
|
||||
+ :doc:`tutorials/signed-interest`
|
||||
+ :doc:`tutorials/certificate-format`
|
||||
+ :doc:`tutorials/security-trust-schema`
|
||||
|
||||
- :doc:`manpages`
|
||||
|
||||
|
||||
@@ -9,3 +9,4 @@ Tutorials
|
||||
tutorials/security-validator-config
|
||||
tutorials/signed-interest
|
||||
tutorials/certificate-format
|
||||
tutorials/security-trust-schema
|
||||
@@ -0,0 +1,423 @@
|
||||
Trust Schema Specification
|
||||
==========================
|
||||
|
||||
.. contents::
|
||||
|
||||
Trust in NDN is based on name. A data packet is valid only if it is signed with a key whose
|
||||
name satisfies certain conditions (e.g., sharing the same prefix, containing certain name
|
||||
components, etc.). Such a relation between data name and key name defines a trust rule. Since
|
||||
keys are just another type of data, authenticating the signing key of a data packet is the same
|
||||
as authenticating a normal data packet. The trust model of an NDN application consists of a
|
||||
set of trust rules that associate data with keys, keys with their signing keys (including some
|
||||
pre-trusted keys).
|
||||
|
||||
Trust schema is a description of a trust model, which can help automate data and interest
|
||||
packet signing and authentication. A trust schema describes the relationship between packet
|
||||
and its signing key in terms of name patterns. A trust schema interpreter with the ability to
|
||||
retrieve public keys (also called *authenticating* *interpreter*) can automatically validate
|
||||
packets according to the trust model. Similarly, a trust schema interpreter with the ability
|
||||
to access private keys (also called *signing* *interpreter*) can automatically sign packets
|
||||
according to the trust model. This specification defines a way to specify a trust model using
|
||||
the trust schema.
|
||||
|
||||
A trust schema consists of three parts: a list of **rules**, one or more
|
||||
**anchor**, and a **crypto**:
|
||||
|
||||
.. table::
|
||||
|
||||
+------------+------------------------------------------------------------------------+
|
||||
| **rule** | Restriction on a packet name and its signing key name |
|
||||
+------------+------------------------------------------------------------------------+
|
||||
| **anchor** | A pre-authenticated public key (a data packet carrying the public key) |
|
||||
+------------+------------------------------------------------------------------------+
|
||||
| **crypto** | Cryptographic requirements on packet signature: which public key |
|
||||
| | algorithm to use, which hashing algorithm to use, and what is the |
|
||||
| | minimum required signature strength |
|
||||
+------------+------------------------------------------------------------------------+
|
||||
|
||||
.. note::
|
||||
All values in trust schema definition must be quoted if they contain spaces.
|
||||
|
||||
Here is an example of the schema configuration file:
|
||||
|
||||
::
|
||||
|
||||
rule
|
||||
{
|
||||
id article
|
||||
name (<>*)<blog><article><><><>
|
||||
signer author($1)
|
||||
}
|
||||
rule
|
||||
{
|
||||
id author
|
||||
name (<>*)<blog><author>[user]<KEY>[id]
|
||||
signer admin($1)
|
||||
}
|
||||
rule
|
||||
{
|
||||
id admin
|
||||
name (<>*)<blog><admin>[user]<KEY>[id]
|
||||
signer admin($1)|root($1)
|
||||
}
|
||||
anchor
|
||||
{
|
||||
id root
|
||||
name (<>*)<blog><KEY>[id]
|
||||
file blog-root.cert
|
||||
}
|
||||
crypto
|
||||
{
|
||||
hash sha256
|
||||
signing rsa|ecdsa
|
||||
key-strength 112
|
||||
}
|
||||
|
||||
An authenticating interpreter that loads this trust schema can automatically
|
||||
validate blog articles, blog author keys, and blog admin keys. When an
|
||||
authenticating interpreter get an article data packet, the interpreter will
|
||||
find the first **rule** whose **name** matches the data name and check the
|
||||
data's KeyLocator against the **signer** in the rule. For example, if the
|
||||
article is signed by an author key which matches the signer **author**, the
|
||||
interpreter can fetch the key and validate the key using the author rule which
|
||||
corresponds to the matched signer. The authentication process can recursively
|
||||
develop until reaching an **anchor**. At this moment, the interpreter can
|
||||
trigger the signature verification along the reverse path until eventually
|
||||
authenticating article.
|
||||
|
||||
Similarly, for packet signing, a signing interpreter that loads this trust
|
||||
schema can construct a chain of signing key to sign packet correctly, so that
|
||||
the packet can be authenticated by authenticating interpreter using the same
|
||||
trust schema.
|
||||
|
||||
Rule
|
||||
----
|
||||
|
||||
A rule has the following properties:
|
||||
|
||||
- **id**: a unique identifier of the rule in the trust schema that can be used to
|
||||
link rules as part of signer "function." The identifier must start with a
|
||||
letter, and can only contain letters, digits, and underscores. The identifier
|
||||
is case-sensitive.
|
||||
|
||||
- **name**: name pattern of the packet in terms of :doc:`utils-ndn-regex`
|
||||
- **type** (optional): type of packet to match against the rule.
|
||||
|
||||
Possible values: **data** (default) and **interest**.
|
||||
|
||||
- **signer**: one or more invocations of rules or trust anchors, separated by **|**.
|
||||
|
||||
Each invocation can take as an input name components that are either explicitly
|
||||
specified or extracted from the packet name using regular expression sub-groups.
|
||||
|
||||
Output of each rule invocation is a name pattern from the corresponding rule or
|
||||
trust anchor, specialized with the specified input parameters.
|
||||
|
||||
Example::
|
||||
|
||||
rule
|
||||
{
|
||||
id article
|
||||
name (<>*)<blog><article><><><>
|
||||
signer author($1)
|
||||
}
|
||||
|
||||
|
||||
A data/interest packet will be checked by a rule only if the packet **name**
|
||||
matches the rule's name property.
|
||||
|
||||
For a packet that is matched by a rule, the packet's KeyLocator will be checked
|
||||
against the rule's **signer** property.
|
||||
|
||||
The packet's KeyLocator must match a name pattern that is derived from at least
|
||||
one of the signers to be treated as a valid packet. Note that KeyLocator always
|
||||
points to a certificate, thus the "functions" in a signer must be data rules.
|
||||
|
||||
.. note::
|
||||
For interest packets, the name property only matches the name components that
|
||||
exist before the packet is signed. In other words, if the signature signing
|
||||
process add the signature info and signature value as name components, these
|
||||
name components will not be matched by the pattern.
|
||||
|
||||
.. note::
|
||||
**ATTENTION: The order of rules MATTERS!** A packet will be check ONLY with
|
||||
the first matched rule.
|
||||
|
||||
|
||||
Anchor
|
||||
------
|
||||
|
||||
A trust schema must contain at least one **anchor** (a pre-authenticated key) and
|
||||
all authentication paths must end at an anchor. Each anchor must contain:
|
||||
|
||||
- **id**: identifier for the anchor that can be used to link an anchor to a rule
|
||||
as a signer "function". The identifier must start with a letter, and can only
|
||||
contain letters, digits, and underscores. The identifier is case-sensitive.
|
||||
|
||||
|
||||
- **name**: name pattern of the packet in terms of :doc:`utils-ndn-regex`
|
||||
|
||||
Since an anchor is pre-authenticated, it does not have the **signer** property,
|
||||
but instead the key directly. Therefore, anchor must specify exactly one of the
|
||||
following properties:
|
||||
|
||||
- **file**: name of a file containing a base64 encoded pre-authenticated public key
|
||||
certificate.
|
||||
|
||||
or
|
||||
|
||||
- **raw**: text string in base64 encoding, containing the raw bytes of a pre-authenticated
|
||||
public key certificate.
|
||||
|
||||
or
|
||||
|
||||
- **dir**: name of directory under which each file contains a base64 encoded
|
||||
pre-authenticated public key certificate.
|
||||
|
||||
|
||||
Examples::
|
||||
|
||||
anchor
|
||||
{
|
||||
id root
|
||||
name (<>*)<blog><KEY>[id]
|
||||
file blog-root.cert
|
||||
}
|
||||
anchor
|
||||
{
|
||||
id another-root
|
||||
name <KEY>[id]
|
||||
raw "Bv0DGwdG...amHFvHIMDw=="
|
||||
}
|
||||
anchor
|
||||
{
|
||||
id root
|
||||
name (<>*)<blog><KEY>[id]
|
||||
dir /etc/ndn/trust-anchors
|
||||
}
|
||||
|
||||
|
||||
When **file** or **dir** is specified and the file(s) can change during the runtime,
|
||||
additional **refresh** property can be specified to define how often the
|
||||
pre-authenticated key should be refreshed in the trust model (Three units of time
|
||||
interval are supported: ``h`` for hour, ``m`` for minute, and ``s`` for second)::
|
||||
|
||||
anchor
|
||||
{
|
||||
id root
|
||||
name (<>*)<blog><KEY>[id]
|
||||
file blog-root.cert
|
||||
refresh 1h ; refresh the key every hour, other units include
|
||||
; m (for minutes) and s (for seconds)
|
||||
}
|
||||
|
||||
There is another special anchor **any**. As long as such an anchor is defined
|
||||
in config file, any signature of any data and interest packet is considered valid::
|
||||
|
||||
anchor
|
||||
{
|
||||
any true
|
||||
}
|
||||
|
||||
.. note::
|
||||
|
||||
Use of ``any`` anchor is highly discouraged and should only be used to
|
||||
temporarily disable packet validation (e.g., while debugging code).
|
||||
|
||||
|
||||
Crypto (Signature Requirements)
|
||||
-------------------------------
|
||||
|
||||
**crypto** block defines the acceptable packet signature.
|
||||
**crypto** must contain three properties:
|
||||
|
||||
- **hash**: one or more allowed hash algorithms, separated by **|**.
|
||||
|
||||
Possible values: **sha256**
|
||||
|
||||
- **signing**: one or more allowed signing algorithms, separated by **|**
|
||||
|
||||
Possible values: **rsa** (RSA signature algorithm), **ecdsa** (ECDSA signature algorithm)
|
||||
|
||||
- **key-strength**: minimum crypto strength of a key (in terms of symmetric key bits)
|
||||
|
||||
Recommended values by NIST (`details`_) and their equivalent RSA and ECDSA key sizes:
|
||||
|
||||
+---------------------------------------------+-------------------+----------------+
|
||||
| Key Strength (in symmetric key bits) | RSA key bits | ECDSA key bits |
|
||||
+=============================================+===================+================+
|
||||
| 80 (very weak) | 1024 | 160 |
|
||||
+---------------------------------------------+-------------------+----------------+
|
||||
| 112 (recommended value) | 2048 | 224 |
|
||||
+---------------------------------------------+-------------------+----------------+
|
||||
| 128 | 3072 | 256 |
|
||||
+---------------------------------------------+-------------------+----------------+
|
||||
| 192 | 7680 | 384 |
|
||||
+---------------------------------------------+-------------------+----------------+
|
||||
| 256 (strong) | 15360 | 521 |
|
||||
+---------------------------------------------+-------------------+----------------+
|
||||
|
||||
.. todo: define key strengths for RSA 4096 (as it is a pretty commonly used value)
|
||||
|
||||
.. _details: http://csrc.nist.gov/publications/nistpubs/800-57/sp800-57_part1_rev3_general.pdf
|
||||
|
||||
..
|
||||
Any
|
||||
---
|
||||
|
||||
There is another special optional property of trust schema **any**. As long as
|
||||
such a property is specified with a value **true**, packet validation will be
|
||||
turned off.
|
||||
|
||||
::
|
||||
|
||||
any true
|
||||
|
||||
.. note::
|
||||
**ATTENTION: This property is dangerous.** You should used it only when you
|
||||
want to disable packet validation temporarily (e.g, debugging code, building
|
||||
a demo).
|
||||
|
||||
Examples
|
||||
--------
|
||||
|
||||
Example Configuration For NLSR
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
The trust model of NLSR is semi-hierarchical. An example certificate signing hierarchy is:
|
||||
|
||||
::
|
||||
|
||||
root
|
||||
|
|
||||
+--------------+---------------+
|
||||
site1 site2
|
||||
| |
|
||||
+---------+---------+ +
|
||||
operator1 operator2 operator3
|
||||
| | |
|
||||
+-----+-----+ +----+-----+ +-----+-----+--------+
|
||||
router1 router2 router3 router4 router5 router6 router7
|
||||
| | | | | | |
|
||||
+ + + + + + +
|
||||
NLSR NSLR NSLR NSLR NSLR NSLR NSLR
|
||||
|
||||
However, entities name may not follow the signing hierarchy, for
|
||||
example:
|
||||
|
||||
+------------+-------------------------------------------------------------------------------------+
|
||||
| Entity | Identity name and examples |
|
||||
+============+=====================================================================================+
|
||||
| root | ``/<network>`` |
|
||||
| | |
|
||||
| | Identity example: ``/ndn`` |
|
||||
| | |
|
||||
| | Certificate name example: ``/ndn/KEY/ksk-1/ID-CERT/%01`` |
|
||||
+------------+-------------------------------------------------------------------------------------+
|
||||
| site | ``/<network>/<site>`` |
|
||||
| | |
|
||||
| | Identity example: ``/ndn/edu/ucla`` |
|
||||
| | |
|
||||
| | Certificate name example: ``/ndn/edu/ucla/KEY/ksk-2/ID-CERT/%01`` |
|
||||
+------------+-------------------------------------------------------------------------------------+
|
||||
| operator | ``/<network>/<site>/%C1.O.N./<operator-id>`` |
|
||||
| | |
|
||||
| | Identity example: ``/ndn/edu/ucla/%C1.O.N./op1`` |
|
||||
| | |
|
||||
| | Certificate name example: ``/ndn/edu/ucla/%C1.O.N./op1/KEY/ksk-3/ID-CERT/%01`` |
|
||||
+------------+-------------------------------------------------------------------------------------+
|
||||
| router | ``/<network>/<site>/%C1.O.R./<router-id>`` |
|
||||
| | |
|
||||
| | Identity example: ``/ndn/edu/ucla/%C1.O.R./rt1`` |
|
||||
| | |
|
||||
| | Certificate name example: ``/ndn/edu/ucla/%C1.O.R./rt1/KEY/ksk-4/ID-CERT/%01`` |
|
||||
+------------+-------------------------------------------------------------------------------------+
|
||||
| NLSR | ``/<network>/<site>/%C1.O.R./<router-id>/NLSR`` |
|
||||
| | |
|
||||
| | Identity example: ``/ndn/edu/ucla/%C1.O.R./rt1/NLSR`` |
|
||||
| | |
|
||||
| | Certificate name example: ``/ndn/edu/ucla/%C1.O.R./rt1/NLSR/KEY/ksk-5/ID-CERT/%01`` |
|
||||
+------------+-------------------------------------------------------------------------------------+
|
||||
|
||||
Assume that a typical NLSR data name is
|
||||
``/ndn/edu/ucla/%C1.O.R./rt1/NLSR/LSA/LSType.1/%01``. Then here is the trust schema:
|
||||
|
||||
::
|
||||
|
||||
rule
|
||||
{
|
||||
id announce
|
||||
name (<>)(<>*)<%C1.O.R.>(<>)<NLSR><LSA><LSType.1>[id]
|
||||
signer nlsr($1,$2,$3)
|
||||
}
|
||||
rule
|
||||
{
|
||||
id nlsr
|
||||
name (<>)(<>*)<%C1.O.R.>(<>)<NLSR><KEY>[id]<ID-CERT>[version]
|
||||
signer router($1,$2,$3)
|
||||
}
|
||||
rule
|
||||
{
|
||||
id router
|
||||
name (<>)(<>*)<%C1.O.R.>(<>)<KEY>[id]<ID-CERT>[version]
|
||||
signer operator($1,$2)
|
||||
}
|
||||
rule
|
||||
{
|
||||
id operator
|
||||
name (<>)(<>*)<%C1.O.N.>[user]<KEY>[id]<ID-CERT>[version]
|
||||
signer site($1)
|
||||
}
|
||||
rule
|
||||
{
|
||||
id site
|
||||
name (<>)(<>*)<KEY>[id]<ID-CERT>[version]
|
||||
signer root($1)
|
||||
}
|
||||
anchor
|
||||
{
|
||||
id root
|
||||
name (<>)<KEY>[id]<ID-CERT>[version]
|
||||
file "testbed-trust-anchor.cert"
|
||||
}
|
||||
crypto
|
||||
{
|
||||
hash sha-256
|
||||
signing rsa|ecdsa
|
||||
key-strength 112
|
||||
}
|
||||
|
||||
Example Configuration For NFD RIB Management
|
||||
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
|
||||
|
||||
Assume `NFD RIB Management <http://redmine.named-data.net/projects/nfd/wiki/RibMgmt>`_
|
||||
allows any valid testbed certificate to register prefix, the configuration file could be
|
||||
written as:
|
||||
|
||||
::
|
||||
|
||||
rule
|
||||
{
|
||||
id localhost-rib-command
|
||||
type interest
|
||||
name <localhost><nrd>[<register><unregister><advertise><withdraw>]<><prefix>(<>*)(<>)
|
||||
signer key($1,$2)
|
||||
}
|
||||
rule
|
||||
{
|
||||
id key
|
||||
name (<>*)(<>)<KEY>[id]<ID-CERT>[version]
|
||||
signer key($1,null)|root()
|
||||
}
|
||||
trust-anchor
|
||||
{
|
||||
id root
|
||||
name <KEY>[id]
|
||||
raw "Bv0DGwdG...amHFvHIMDw=="
|
||||
}
|
||||
crypto
|
||||
{
|
||||
hash sha-256
|
||||
signing rsa|ecdsa
|
||||
key-strength 112
|
||||
}
|
||||
@@ -0,0 +1,62 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received copies of the GNU General Public License and GNU Lesser
|
||||
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*/
|
||||
|
||||
#include "regex-backref-matcher.hpp"
|
||||
|
||||
#include "regex-pattern-list-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
RegexBackrefMatcher::RegexBackrefMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager)
|
||||
: RegexMatcher(expr, EXPR_BACKREF, backrefManager)
|
||||
{
|
||||
}
|
||||
|
||||
RegexBackrefMatcher::~RegexBackrefMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RegexBackrefMatcher::lateCompile()
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
void
|
||||
RegexBackrefMatcher::compile()
|
||||
{
|
||||
if (m_expr.size() < 2)
|
||||
throw Error("Unrecognized format: " + m_expr);
|
||||
|
||||
size_t lastIndex = m_expr.size() - 1;
|
||||
if ('(' == m_expr[0] && ')' == m_expr[lastIndex]) {
|
||||
// m_backRefManager->pushRef(this);
|
||||
|
||||
auto matcher = make_shared<RegexPatternListMatcher>(m_expr.substr(1, lastIndex - 1),
|
||||
m_backrefManager);
|
||||
m_matchers.push_back(matcher);
|
||||
}
|
||||
else
|
||||
throw Error("Unrecognized format: " + m_expr);
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#ifndef NDN_UTIL_REGEX_REGEX_BACKREF_MATCHER_HPP
|
||||
@@ -36,54 +34,16 @@ public:
|
||||
RegexBackrefMatcher(const std::string& expr, shared_ptr<RegexBackrefManager> backrefManager);
|
||||
|
||||
virtual
|
||||
~RegexBackrefMatcher()
|
||||
{
|
||||
}
|
||||
~RegexBackrefMatcher() NDN_CXX_DECL_FINAL;
|
||||
|
||||
void
|
||||
lateCompile()
|
||||
{
|
||||
compile();
|
||||
}
|
||||
lateCompile();
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
compile();
|
||||
compile() NDN_CXX_DECL_FINAL;
|
||||
};
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#include "regex-pattern-list-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
inline
|
||||
RegexBackrefMatcher::RegexBackrefMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager)
|
||||
: RegexMatcher(expr, EXPR_BACKREF, backrefManager)
|
||||
{
|
||||
// compile();
|
||||
}
|
||||
|
||||
inline void
|
||||
RegexBackrefMatcher::compile()
|
||||
{
|
||||
if (m_expr.size() < 2)
|
||||
throw RegexMatcher::Error("Unrecognized format: " + m_expr);
|
||||
|
||||
size_t lastIndex = m_expr.size() - 1;
|
||||
if ('(' == m_expr[0] && ')' == m_expr[lastIndex]) {
|
||||
// m_backRefManager->pushRef(this);
|
||||
|
||||
shared_ptr<RegexMatcher> matcher(new RegexPatternListMatcher(m_expr.substr(1, lastIndex - 1),
|
||||
m_backrefManager));
|
||||
m_matchers.push_back(matcher);
|
||||
}
|
||||
else
|
||||
throw RegexMatcher::Error("Unrecognized format: " + m_expr);
|
||||
}
|
||||
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_UTIL_REGEX_REGEX_BACKREF_MATCHER_HPP
|
||||
@@ -0,0 +1,97 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received copies of the GNU General Public License and GNU Lesser
|
||||
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*/
|
||||
|
||||
#include "regex-component-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
// Re: http://www.boost.org/users/history/version_1_56_0.html
|
||||
//
|
||||
// Breaking change: corrected behavior of basic_regex<>::mark_count() to match existing
|
||||
// documentation, basic_regex<>::subexpression(n) changed to match, see
|
||||
// https://svn.boost.org/trac/boost/ticket/9227
|
||||
static const size_t BOOST_REGEXP_MARK_COUNT_CORRECTION =
|
||||
#if BOOST_VERSION < 105600
|
||||
1;
|
||||
#else
|
||||
0;
|
||||
#endif
|
||||
|
||||
RegexComponentMatcher::RegexComponentMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager,
|
||||
bool isExactMatch)
|
||||
: RegexMatcher(expr, EXPR_COMPONENT, backrefManager)
|
||||
, m_isExactMatch(isExactMatch)
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
RegexComponentMatcher::~RegexComponentMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
RegexComponentMatcher::match(const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
m_matchResult.clear();
|
||||
|
||||
if (m_expr.empty()) {
|
||||
m_matchResult.push_back(name.get(offset));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_isExactMatch) {
|
||||
boost::smatch subResult;
|
||||
std::string targetStr = name.get(offset).toUri();
|
||||
if (boost::regex_match(targetStr, subResult, m_componentRegex)) {
|
||||
for (size_t i = 1;
|
||||
i <= m_componentRegex.mark_count() - BOOST_REGEXP_MARK_COUNT_CORRECTION; i++) {
|
||||
m_pseudoMatchers[i]->resetMatchResult();
|
||||
m_pseudoMatchers[i]->setMatchResult(subResult[i]);
|
||||
}
|
||||
m_matchResult.push_back(name.get(offset));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
throw Error("Non-exact component search is not supported yet!");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
RegexComponentMatcher::compile()
|
||||
{
|
||||
m_componentRegex = boost::regex(m_expr);
|
||||
|
||||
m_pseudoMatchers.clear();
|
||||
m_pseudoMatchers.push_back(make_shared<RegexPseudoMatcher>());
|
||||
|
||||
for (size_t i = 1;
|
||||
i <= m_componentRegex.mark_count() - BOOST_REGEXP_MARK_COUNT_CORRECTION; i++) {
|
||||
auto pMatcher = make_shared<RegexPseudoMatcher>();
|
||||
m_pseudoMatchers.push_back(pMatcher);
|
||||
m_backrefManager->pushRef(static_pointer_cast<RegexMatcher>(pMatcher));
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#ifndef NDN_UTIL_REGEX_REGEX_COMPONENT_MATCHER_HPP
|
||||
@@ -45,12 +43,10 @@ public:
|
||||
bool isExactMatch = true);
|
||||
|
||||
virtual
|
||||
~RegexComponentMatcher()
|
||||
{
|
||||
};
|
||||
~RegexComponentMatcher() NDN_CXX_DECL_FINAL;
|
||||
|
||||
virtual bool
|
||||
match(const Name& name, size_t offset, size_t len = 1);
|
||||
match(const Name& name, size_t offset, size_t len = 1) NDN_CXX_DECL_FINAL;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -58,7 +54,7 @@ protected:
|
||||
* @returns true if compiling succeeds
|
||||
*/
|
||||
virtual void
|
||||
compile();
|
||||
compile() NDN_CXX_DECL_FINAL;
|
||||
|
||||
private:
|
||||
bool m_isExactMatch;
|
||||
@@ -67,82 +63,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
|
||||
inline
|
||||
RegexComponentMatcher::RegexComponentMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager,
|
||||
bool isExactMatch)
|
||||
: RegexMatcher(expr, EXPR_COMPONENT, backrefManager)
|
||||
, m_isExactMatch(isExactMatch)
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
// Re: http://www.boost.org/users/history/version_1_56_0.html
|
||||
//
|
||||
// Breaking change: corrected behavior of basic_regex<>::mark_count() to match existing
|
||||
// documentation, basic_regex<>::subexpression(n) changed to match, see
|
||||
// https://svn.boost.org/trac/boost/ticket/9227
|
||||
static const size_t BOOST_REGEXP_MARK_COUNT_CORRECTION =
|
||||
#if BOOST_VERSION < 105600
|
||||
1;
|
||||
#else
|
||||
0;
|
||||
#endif
|
||||
|
||||
inline void
|
||||
RegexComponentMatcher::compile()
|
||||
{
|
||||
m_componentRegex = boost::regex(m_expr);
|
||||
|
||||
m_pseudoMatchers.clear();
|
||||
m_pseudoMatchers.push_back(make_shared<RegexPseudoMatcher>());
|
||||
|
||||
for (size_t i = 1;
|
||||
i <= m_componentRegex.mark_count() - BOOST_REGEXP_MARK_COUNT_CORRECTION; i++)
|
||||
{
|
||||
shared_ptr<RegexPseudoMatcher> pMatcher = make_shared<RegexPseudoMatcher>();
|
||||
m_pseudoMatchers.push_back(pMatcher);
|
||||
m_backrefManager->pushRef(static_pointer_cast<RegexMatcher>(pMatcher));
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegexComponentMatcher::match(const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
m_matchResult.clear();
|
||||
|
||||
if (m_expr.empty())
|
||||
{
|
||||
m_matchResult.push_back(name.get(offset));
|
||||
return true;
|
||||
}
|
||||
|
||||
if (m_isExactMatch)
|
||||
{
|
||||
boost::smatch subResult;
|
||||
std::string targetStr = name.get(offset).toUri();
|
||||
if (boost::regex_match(targetStr, subResult, m_componentRegex))
|
||||
{
|
||||
for (size_t i = 1;
|
||||
i <= m_componentRegex.mark_count() - BOOST_REGEXP_MARK_COUNT_CORRECTION; i++)
|
||||
{
|
||||
m_pseudoMatchers[i]->resetMatchResult();
|
||||
m_pseudoMatchers[i]->setMatchResult(subResult[i]);
|
||||
}
|
||||
m_matchResult.push_back(name.get(offset));
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
throw RegexMatcher::Error("Non-exact component search is not supported yet!");
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_UTIL_REGEX_REGEX_COMPONENT_MATCHER_HPP
|
||||
@@ -0,0 +1,161 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received copies of the GNU General Public License and GNU Lesser
|
||||
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*/
|
||||
|
||||
#include "regex-component-set-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
RegexComponentSetMatcher::RegexComponentSetMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager)
|
||||
: RegexMatcher(expr, EXPR_COMPONENT_SET, backrefManager)
|
||||
, m_isInclusion(true)
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
RegexComponentSetMatcher::~RegexComponentSetMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
RegexComponentSetMatcher::match(const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
bool isMatched = false;
|
||||
|
||||
/* componentset only matches one component */
|
||||
if (len != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (auto& component : m_components) {
|
||||
if (component->match(name, offset, len)) {
|
||||
isMatched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_matchResult.clear();
|
||||
|
||||
if (m_isInclusion ? isMatched : !isMatched) {
|
||||
m_matchResult.push_back(name.get(offset));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
RegexComponentSetMatcher::compile()
|
||||
{
|
||||
if (m_expr.size() < 2)
|
||||
throw Error("Regexp compile error (cannot parse " + m_expr + ")");
|
||||
|
||||
switch (m_expr[0]) {
|
||||
case '<':
|
||||
return compileSingleComponent();
|
||||
case '[':
|
||||
{
|
||||
size_t lastIndex = m_expr.size() - 1;
|
||||
if (']' != m_expr[lastIndex])
|
||||
throw Error("Regexp compile error (no matching ']' in " + m_expr + ")");
|
||||
|
||||
if ('^' == m_expr[1]) {
|
||||
m_isInclusion = false;
|
||||
compileMultipleComponents(2, lastIndex);
|
||||
}
|
||||
else
|
||||
compileMultipleComponents(1, lastIndex);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw Error("Regexp compile error (cannot parse " + m_expr + ")");
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegexComponentSetMatcher::compileSingleComponent()
|
||||
{
|
||||
size_t end = extractComponent(1);
|
||||
|
||||
if (m_expr.size() != end) {
|
||||
throw Error("Component expr error " + m_expr);
|
||||
}
|
||||
else {
|
||||
auto component = make_shared<RegexComponentMatcher>(m_expr.substr(1, end - 2),
|
||||
m_backrefManager);
|
||||
|
||||
m_components.insert(component);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
RegexComponentSetMatcher::compileMultipleComponents(size_t start, size_t lastIndex)
|
||||
{
|
||||
size_t index = start;
|
||||
size_t tempIndex = start;
|
||||
|
||||
while (index < lastIndex) {
|
||||
if ('<' != m_expr[index])
|
||||
throw Error("Component expr error " + m_expr);
|
||||
|
||||
tempIndex = index + 1;
|
||||
index = extractComponent(tempIndex);
|
||||
|
||||
auto component = make_shared<RegexComponentMatcher>(m_expr.substr(tempIndex,
|
||||
index - tempIndex - 1),
|
||||
m_backrefManager);
|
||||
|
||||
m_components.insert(component);
|
||||
}
|
||||
|
||||
if (index != lastIndex)
|
||||
throw Error("Not sufficient expr to parse " + m_expr);
|
||||
}
|
||||
|
||||
size_t
|
||||
RegexComponentSetMatcher::extractComponent(size_t index)
|
||||
{
|
||||
size_t lcount = 1;
|
||||
size_t rcount = 0;
|
||||
|
||||
while (lcount > rcount) {
|
||||
switch (m_expr[index]) {
|
||||
case '<':
|
||||
lcount++;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
rcount++;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
throw Error("Error: square brackets mismatch");
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#ifndef NDN_UTIL_REGEX_COMPONENT_SET_MATCHER_HPP
|
||||
@@ -44,10 +42,10 @@ public:
|
||||
RegexComponentSetMatcher(const std::string& expr, shared_ptr<RegexBackrefManager> backrefManager);
|
||||
|
||||
virtual
|
||||
~RegexComponentSetMatcher();
|
||||
~RegexComponentSetMatcher() NDN_CXX_DECL_FINAL;
|
||||
|
||||
virtual bool
|
||||
match(const Name& name, size_t offset, size_t len = 1);
|
||||
match(const Name& name, size_t offset, size_t len = 1) NDN_CXX_DECL_FINAL;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -55,7 +53,7 @@ protected:
|
||||
* @returns true if compiling succeeds
|
||||
*/
|
||||
virtual void
|
||||
compile();
|
||||
compile() NDN_CXX_DECL_FINAL;
|
||||
|
||||
private:
|
||||
size_t
|
||||
@@ -73,151 +71,6 @@ private:
|
||||
bool m_isInclusion;
|
||||
};
|
||||
|
||||
|
||||
inline
|
||||
RegexComponentSetMatcher::RegexComponentSetMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager)
|
||||
: RegexMatcher(expr, EXPR_COMPONENT_SET, backrefManager)
|
||||
, m_isInclusion(true)
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
inline
|
||||
RegexComponentSetMatcher::~RegexComponentSetMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
inline void
|
||||
RegexComponentSetMatcher::compile()
|
||||
{
|
||||
if (m_expr.size() < 2)
|
||||
throw RegexMatcher::Error("Regexp compile error (cannot parse " + m_expr + ")");
|
||||
|
||||
switch (m_expr[0]) {
|
||||
case '<':
|
||||
return compileSingleComponent();
|
||||
case '[':
|
||||
{
|
||||
size_t lastIndex = m_expr.size() - 1;
|
||||
if (']' != m_expr[lastIndex])
|
||||
throw RegexMatcher::Error("Regexp compile error (no matching ']' in " + m_expr + ")");
|
||||
|
||||
if ('^' == m_expr[1]) {
|
||||
m_isInclusion = false;
|
||||
compileMultipleComponents(2, lastIndex);
|
||||
}
|
||||
else
|
||||
compileMultipleComponents(1, lastIndex);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
throw RegexMatcher::Error("Regexp compile error (cannot parse " + m_expr + ")");
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
RegexComponentSetMatcher::compileSingleComponent()
|
||||
{
|
||||
size_t end = extractComponent(1);
|
||||
|
||||
if (m_expr.size() != end)
|
||||
{
|
||||
throw RegexMatcher::Error("Component expr error " + m_expr);
|
||||
}
|
||||
else
|
||||
{
|
||||
shared_ptr<RegexComponentMatcher> component =
|
||||
make_shared<RegexComponentMatcher>(m_expr.substr(1, end - 2), m_backrefManager);
|
||||
|
||||
m_components.insert(component);
|
||||
}
|
||||
}
|
||||
|
||||
inline void
|
||||
RegexComponentSetMatcher::compileMultipleComponents(size_t start, size_t lastIndex)
|
||||
{
|
||||
size_t index = start;
|
||||
size_t tempIndex = start;
|
||||
|
||||
while (index < lastIndex) {
|
||||
if ('<' != m_expr[index])
|
||||
throw RegexMatcher::Error("Component expr error " + m_expr);
|
||||
|
||||
tempIndex = index + 1;
|
||||
index = extractComponent(tempIndex);
|
||||
|
||||
shared_ptr<RegexComponentMatcher> component =
|
||||
make_shared<RegexComponentMatcher>(m_expr.substr(tempIndex, index - tempIndex - 1),
|
||||
m_backrefManager);
|
||||
|
||||
m_components.insert(component);
|
||||
}
|
||||
|
||||
if (index != lastIndex)
|
||||
throw RegexMatcher::Error("Not sufficient expr to parse " + m_expr);
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegexComponentSetMatcher::match(const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
bool isMatched = false;
|
||||
|
||||
/* componentset only matches one component */
|
||||
if (len != 1)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
for (ComponentsSet::iterator it = m_components.begin();
|
||||
it != m_components.end();
|
||||
++it)
|
||||
{
|
||||
if ((*it)->match(name, offset, len))
|
||||
{
|
||||
isMatched = true;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
m_matchResult.clear();
|
||||
|
||||
if (m_isInclusion ? isMatched : !isMatched)
|
||||
{
|
||||
m_matchResult.push_back(name.get(offset));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline size_t
|
||||
RegexComponentSetMatcher::extractComponent(size_t index)
|
||||
{
|
||||
size_t lcount = 1;
|
||||
size_t rcount = 0;
|
||||
|
||||
while (lcount > rcount) {
|
||||
switch (m_expr[index]) {
|
||||
case '<':
|
||||
lcount++;
|
||||
break;
|
||||
|
||||
case '>':
|
||||
rcount++;
|
||||
break;
|
||||
|
||||
case 0:
|
||||
throw RegexMatcher::Error("Error: square brackets mismatch");
|
||||
break;
|
||||
}
|
||||
index++;
|
||||
|
||||
}
|
||||
|
||||
return index;
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_UTIL_REGEX_COMPONENT_SET_MATCHER_HPP
|
||||
@@ -0,0 +1,80 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received copies of the GNU General Public License and GNU Lesser
|
||||
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*/
|
||||
|
||||
#include "regex-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
RegexMatcher::RegexMatcher(const std::string& expr,
|
||||
const RegexExprType& type,
|
||||
shared_ptr<RegexBackrefManager> backrefManager)
|
||||
: m_expr(expr)
|
||||
, m_type(type)
|
||||
, m_backrefManager(backrefManager)
|
||||
{
|
||||
if (!static_cast<bool>(m_backrefManager))
|
||||
m_backrefManager = make_shared<RegexBackrefManager>();
|
||||
}
|
||||
|
||||
RegexMatcher::~RegexMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
RegexMatcher::match(const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
m_matchResult.clear();
|
||||
|
||||
if (recursiveMatch(0, name, offset, len)) {
|
||||
for (size_t i = offset; i < offset + len ; i++)
|
||||
m_matchResult.push_back(name.get(i));
|
||||
result = true;
|
||||
}
|
||||
else {
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
bool
|
||||
RegexMatcher::recursiveMatch(size_t matcherNo, const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
ssize_t tried = len;
|
||||
|
||||
if (matcherNo >= m_matchers.size())
|
||||
return (len == 0);
|
||||
|
||||
shared_ptr<RegexMatcher> matcher = m_matchers[matcherNo];
|
||||
|
||||
while (tried >= 0) {
|
||||
if (matcher->match(name, offset, tried) &&
|
||||
recursiveMatch(matcherNo + 1, name, offset + tried, len - tried))
|
||||
return true;
|
||||
tried--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#ifndef NDN_UTIL_REGEX_REGEX_MATCHER_H
|
||||
@@ -26,11 +24,10 @@
|
||||
|
||||
#include "../../common.hpp"
|
||||
#include "../../name.hpp"
|
||||
#include "regex-backref-manager.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
class RegexBackrefManager;
|
||||
|
||||
class RegexMatcher
|
||||
{
|
||||
public:
|
||||
@@ -56,7 +53,7 @@ public:
|
||||
|
||||
RegexMatcher(const std::string& expr,
|
||||
const RegexExprType& type,
|
||||
shared_ptr<RegexBackrefManager> backrefManager = shared_ptr<RegexBackrefManager>());
|
||||
shared_ptr<RegexBackrefManager> backrefManager = nullptr);
|
||||
|
||||
virtual
|
||||
~RegexMatcher();
|
||||
@@ -110,71 +107,4 @@ operator<<(std::ostream& os, const RegexMatcher& regex)
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#include "regex-backref-manager.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
inline
|
||||
RegexMatcher::RegexMatcher(const std::string& expr,
|
||||
const RegexExprType& type,
|
||||
shared_ptr<RegexBackrefManager> backrefManager)
|
||||
: m_expr(expr)
|
||||
, m_type(type)
|
||||
, m_backrefManager(backrefManager)
|
||||
{
|
||||
if (!static_cast<bool>(m_backrefManager))
|
||||
m_backrefManager = make_shared<RegexBackrefManager>();
|
||||
}
|
||||
|
||||
inline
|
||||
RegexMatcher::~RegexMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegexMatcher::match(const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
bool result = false;
|
||||
|
||||
m_matchResult.clear();
|
||||
|
||||
if (recursiveMatch(0, name, offset, len))
|
||||
{
|
||||
for (size_t i = offset; i < offset + len ; i++)
|
||||
m_matchResult.push_back(name.get(i));
|
||||
result = true;
|
||||
}
|
||||
else
|
||||
{
|
||||
result = false;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegexMatcher::recursiveMatch(size_t matcherNo, const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
ssize_t tried = len;
|
||||
|
||||
if (matcherNo >= m_matchers.size())
|
||||
return (len == 0);
|
||||
|
||||
shared_ptr<RegexMatcher> matcher = m_matchers[matcherNo];
|
||||
|
||||
while (tried >= 0)
|
||||
{
|
||||
if (matcher->match(name, offset, tried) &&
|
||||
recursiveMatch(matcherNo + 1, name, offset + tried, len - tried))
|
||||
return true;
|
||||
tried--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
|
||||
#endif // NDN_UTIL_REGEX_REGEX_MATCHER_H
|
||||
@@ -0,0 +1,159 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received copies of the GNU General Public License and GNU Lesser
|
||||
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*/
|
||||
|
||||
#include "regex-pattern-list-matcher.hpp"
|
||||
|
||||
#include "regex-repeat-matcher.hpp"
|
||||
#include "regex-backref-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
RegexPatternListMatcher::RegexPatternListMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager)
|
||||
: RegexMatcher(expr, EXPR_PATTERN_LIST, backrefManager)
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
RegexPatternListMatcher::~RegexPatternListMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RegexPatternListMatcher::compile()
|
||||
{
|
||||
size_t len = m_expr.size();
|
||||
size_t index = 0;
|
||||
size_t subHead = index;
|
||||
|
||||
while (index < len) {
|
||||
subHead = index;
|
||||
|
||||
if (!extractPattern(subHead, &index))
|
||||
throw Error("Compile error");
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
RegexPatternListMatcher::extractPattern(size_t index, size_t* next)
|
||||
{
|
||||
size_t start = index;
|
||||
size_t end = index;
|
||||
size_t indicator = index;
|
||||
|
||||
switch (m_expr[index]) {
|
||||
case '(':
|
||||
index++;
|
||||
index = extractSubPattern('(', ')', index);
|
||||
indicator = index;
|
||||
end = extractRepetition(index);
|
||||
if (indicator == end) {
|
||||
auto matcher = make_shared<RegexBackrefMatcher>(m_expr.substr(start, end - start),
|
||||
m_backrefManager);
|
||||
m_backrefManager->pushRef(matcher);
|
||||
dynamic_pointer_cast<RegexBackrefMatcher>(matcher)->lateCompile();
|
||||
|
||||
m_matchers.push_back(matcher);
|
||||
}
|
||||
else
|
||||
m_matchers.push_back(make_shared<RegexRepeatMatcher>(m_expr.substr(start, end - start),
|
||||
m_backrefManager, indicator - start));
|
||||
break;
|
||||
|
||||
case '<':
|
||||
index++;
|
||||
index = extractSubPattern('<', '>', index);
|
||||
indicator = index;
|
||||
end = extractRepetition(index);
|
||||
m_matchers.push_back(make_shared<RegexRepeatMatcher>(m_expr.substr(start, end - start),
|
||||
m_backrefManager, indicator - start));
|
||||
break;
|
||||
|
||||
case '[':
|
||||
index++;
|
||||
index = extractSubPattern('[', ']', index);
|
||||
indicator = index;
|
||||
end = extractRepetition(index);
|
||||
m_matchers.push_back(make_shared<RegexRepeatMatcher>(m_expr.substr(start, end - start),
|
||||
m_backrefManager, indicator - start));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw Error("Unexpected syntax");
|
||||
}
|
||||
|
||||
*next = end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
int
|
||||
RegexPatternListMatcher::extractSubPattern(const char left, const char right, size_t index)
|
||||
{
|
||||
size_t lcount = 1;
|
||||
size_t rcount = 0;
|
||||
|
||||
while (lcount > rcount) {
|
||||
|
||||
if (index >= m_expr.size())
|
||||
throw Error("Parenthesis mismatch");
|
||||
|
||||
if (left == m_expr[index])
|
||||
lcount++;
|
||||
|
||||
if (right == m_expr[index])
|
||||
rcount++;
|
||||
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
int
|
||||
RegexPatternListMatcher::extractRepetition(size_t index)
|
||||
{
|
||||
size_t exprSize = m_expr.size();
|
||||
|
||||
if (index == exprSize)
|
||||
return index;
|
||||
|
||||
if (('+' == m_expr[index] || '?' == m_expr[index] || '*' == m_expr[index])) {
|
||||
return ++index;
|
||||
}
|
||||
|
||||
if ('{' == m_expr[index]) {
|
||||
while ('}' != m_expr[index]) {
|
||||
index++;
|
||||
if (index == exprSize)
|
||||
break;
|
||||
}
|
||||
if (index == exprSize)
|
||||
throw Error("Missing right brace bracket");
|
||||
else
|
||||
return ++index;
|
||||
}
|
||||
else {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#ifndef NDN_UTIL_REGEX_REGEX_PATTERN_LIST_MATCHER_HPP
|
||||
@@ -38,13 +36,11 @@ public:
|
||||
RegexPatternListMatcher(const std::string& expr, shared_ptr<RegexBackrefManager> backrefManager);
|
||||
|
||||
virtual
|
||||
~RegexPatternListMatcher()
|
||||
{
|
||||
};
|
||||
~RegexPatternListMatcher() NDN_CXX_DECL_FINAL;
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
compile();
|
||||
compile() NDN_CXX_DECL_FINAL;
|
||||
|
||||
private:
|
||||
bool
|
||||
@@ -60,140 +56,6 @@ private:
|
||||
|
||||
};
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#include "regex-repeat-matcher.hpp"
|
||||
#include "regex-backref-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
inline
|
||||
RegexPatternListMatcher::RegexPatternListMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager)
|
||||
: RegexMatcher(expr, EXPR_PATTERN_LIST, backrefManager)
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
inline void
|
||||
RegexPatternListMatcher::compile()
|
||||
{
|
||||
size_t len = m_expr.size();
|
||||
size_t index = 0;
|
||||
size_t subHead = index;
|
||||
|
||||
while (index < len) {
|
||||
subHead = index;
|
||||
|
||||
if (!extractPattern(subHead, &index))
|
||||
throw RegexMatcher::Error("Compile error");
|
||||
}
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegexPatternListMatcher::extractPattern(size_t index, size_t* next)
|
||||
{
|
||||
size_t start = index;
|
||||
size_t end = index;
|
||||
size_t indicator = index;
|
||||
|
||||
switch (m_expr[index]) {
|
||||
case '(':
|
||||
index++;
|
||||
index = extractSubPattern('(', ')', index);
|
||||
indicator = index;
|
||||
end = extractRepetition(index);
|
||||
if (indicator == end) {
|
||||
shared_ptr<RegexMatcher> matcher =
|
||||
make_shared<RegexBackrefMatcher>(m_expr.substr(start, end - start), m_backrefManager);
|
||||
m_backrefManager->pushRef(matcher);
|
||||
dynamic_pointer_cast<RegexBackrefMatcher>(matcher)->lateCompile();
|
||||
|
||||
m_matchers.push_back(matcher);
|
||||
}
|
||||
else
|
||||
m_matchers.push_back(make_shared<RegexRepeatMatcher>(m_expr.substr(start, end - start),
|
||||
m_backrefManager, indicator - start));
|
||||
break;
|
||||
|
||||
case '<':
|
||||
index++;
|
||||
index = extractSubPattern('<', '>', index);
|
||||
indicator = index;
|
||||
end = extractRepetition(index);
|
||||
m_matchers.push_back(make_shared<RegexRepeatMatcher>(m_expr.substr(start, end - start),
|
||||
m_backrefManager, indicator - start));
|
||||
break;
|
||||
|
||||
case '[':
|
||||
index++;
|
||||
index = extractSubPattern('[', ']', index);
|
||||
indicator = index;
|
||||
end = extractRepetition(index);
|
||||
m_matchers.push_back(make_shared<RegexRepeatMatcher>(m_expr.substr(start, end - start),
|
||||
m_backrefManager, indicator - start));
|
||||
break;
|
||||
|
||||
default:
|
||||
throw RegexMatcher::Error("Unexpected syntax");
|
||||
}
|
||||
|
||||
*next = end;
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
inline int
|
||||
RegexPatternListMatcher::extractSubPattern(const char left, const char right, size_t index)
|
||||
{
|
||||
size_t lcount = 1;
|
||||
size_t rcount = 0;
|
||||
|
||||
while (lcount > rcount) {
|
||||
|
||||
if (index >= m_expr.size())
|
||||
throw RegexMatcher::Error("Parenthesis mismatch");
|
||||
|
||||
if (left == m_expr[index])
|
||||
lcount++;
|
||||
|
||||
if (right == m_expr[index])
|
||||
rcount++;
|
||||
|
||||
index++;
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
inline int
|
||||
RegexPatternListMatcher::extractRepetition(size_t index)
|
||||
{
|
||||
size_t exprSize = m_expr.size();
|
||||
|
||||
if (index == exprSize)
|
||||
return index;
|
||||
|
||||
if (('+' == m_expr[index] || '?' == m_expr[index] || '*' == m_expr[index])) {
|
||||
return ++index;
|
||||
}
|
||||
|
||||
if ('{' == m_expr[index]) {
|
||||
while ('}' != m_expr[index]) {
|
||||
index++;
|
||||
if (index == exprSize)
|
||||
break;
|
||||
}
|
||||
if (index == exprSize)
|
||||
throw RegexMatcher::Error("Missing right brace bracket");
|
||||
else
|
||||
return ++index;
|
||||
}
|
||||
else {
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_UTIL_REGEX_REGEX_PATTERN_LIST_MATCHER_HPP
|
||||
@@ -0,0 +1,53 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received copies of the GNU General Public License and GNU Lesser
|
||||
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*/
|
||||
|
||||
#include "regex-pseudo-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
RegexPseudoMatcher::RegexPseudoMatcher()
|
||||
: RegexMatcher("", EXPR_PSEUDO)
|
||||
{
|
||||
}
|
||||
|
||||
RegexPseudoMatcher::~RegexPseudoMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RegexPseudoMatcher::compile()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
RegexPseudoMatcher::setMatchResult(const std::string& str)
|
||||
{
|
||||
m_matchResult.push_back(name::Component(reinterpret_cast<const uint8_t*>(str.c_str()),
|
||||
str.size()));
|
||||
}
|
||||
|
||||
void
|
||||
RegexPseudoMatcher::resetMatchResult()
|
||||
{
|
||||
m_matchResult.clear();
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#ifndef NDN_UTIL_REGEX_REGEX_PSEUDO_MATCHER_HPP
|
||||
@@ -35,14 +33,10 @@ public:
|
||||
RegexPseudoMatcher();
|
||||
|
||||
virtual
|
||||
~RegexPseudoMatcher()
|
||||
{
|
||||
}
|
||||
~RegexPseudoMatcher() NDN_CXX_DECL_FINAL;
|
||||
|
||||
virtual void
|
||||
compile()
|
||||
{
|
||||
}
|
||||
compile() NDN_CXX_DECL_FINAL;
|
||||
|
||||
void
|
||||
setMatchResult(const std::string& str);
|
||||
@@ -51,26 +45,6 @@ public:
|
||||
resetMatchResult();
|
||||
};
|
||||
|
||||
inline
|
||||
RegexPseudoMatcher::RegexPseudoMatcher()
|
||||
: RegexMatcher("", EXPR_PSEUDO)
|
||||
{
|
||||
}
|
||||
|
||||
inline void
|
||||
RegexPseudoMatcher::setMatchResult(const std::string& str)
|
||||
{
|
||||
m_matchResult.push_back(name::Component(reinterpret_cast<const uint8_t*>(str.c_str()),
|
||||
str.size()));
|
||||
}
|
||||
|
||||
inline void
|
||||
RegexPseudoMatcher::resetMatchResult()
|
||||
{
|
||||
m_matchResult.clear();
|
||||
}
|
||||
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_UTIL_REGEX_REGEX_PSEUDO_MATCHER_HPP
|
||||
@@ -0,0 +1,178 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
* ndn-cxx library is free software: you can redistribute it and/or modify it under the
|
||||
* terms of the GNU Lesser General Public License as published by the Free Software
|
||||
* Foundation, either version 3 of the License, or (at your option) any later version.
|
||||
*
|
||||
* ndn-cxx library is distributed in the hope that it will be useful, but WITHOUT ANY
|
||||
* WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR A
|
||||
* PARTICULAR PURPOSE. See the GNU Lesser General Public License for more details.
|
||||
*
|
||||
* You should have received copies of the GNU General Public License and GNU Lesser
|
||||
* General Public License along with ndn-cxx, e.g., in COPYING.md file. If not, see
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*/
|
||||
|
||||
#include "regex-repeat-matcher.hpp"
|
||||
|
||||
#include "regex-backref-matcher.hpp"
|
||||
#include "regex-component-set-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
RegexRepeatMatcher::RegexRepeatMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager,
|
||||
size_t indicator)
|
||||
: RegexMatcher(expr, EXPR_REPEAT_PATTERN, backrefManager)
|
||||
, m_indicator(indicator)
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
RegexRepeatMatcher::~RegexRepeatMatcher()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
RegexRepeatMatcher::match(const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
m_matchResult.clear();
|
||||
|
||||
if (0 == m_repeatMin)
|
||||
if (0 == len)
|
||||
return true;
|
||||
|
||||
if (recursiveMatch(0, name, offset, len)) {
|
||||
for (size_t i = offset; i < offset + len; i++)
|
||||
m_matchResult.push_back(name.get(i));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
RegexRepeatMatcher::compile()
|
||||
{
|
||||
shared_ptr<RegexMatcher> matcher;
|
||||
|
||||
if ('(' == m_expr[0]) {
|
||||
matcher = make_shared<RegexBackrefMatcher>(m_expr.substr(0, m_indicator), m_backrefManager);
|
||||
m_backrefManager->pushRef(matcher);
|
||||
dynamic_pointer_cast<RegexBackrefMatcher>(matcher)->lateCompile();
|
||||
}
|
||||
else{
|
||||
matcher = make_shared<RegexComponentSetMatcher>(m_expr.substr(0, m_indicator),
|
||||
m_backrefManager);
|
||||
}
|
||||
m_matchers.push_back(matcher);
|
||||
|
||||
parseRepetition();
|
||||
}
|
||||
|
||||
bool
|
||||
RegexRepeatMatcher::parseRepetition()
|
||||
{
|
||||
size_t exprSize = m_expr.size();
|
||||
const size_t MAX_REPETITIONS = std::numeric_limits<size_t>::max();
|
||||
|
||||
if (exprSize == m_indicator) {
|
||||
m_repeatMin = 1;
|
||||
m_repeatMax = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (exprSize == (m_indicator + 1)) {
|
||||
if ('?' == m_expr[m_indicator]) {
|
||||
m_repeatMin = 0;
|
||||
m_repeatMax = 1;
|
||||
return true;
|
||||
}
|
||||
if ('+' == m_expr[m_indicator]) {
|
||||
m_repeatMin = 1;
|
||||
m_repeatMax = MAX_REPETITIONS;
|
||||
return true;
|
||||
}
|
||||
if ('*' == m_expr[m_indicator]) {
|
||||
m_repeatMin = 0;
|
||||
m_repeatMax = MAX_REPETITIONS;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string repeatStruct = m_expr.substr(m_indicator, exprSize - m_indicator);
|
||||
size_t rsSize = repeatStruct.size();
|
||||
size_t min = 0;
|
||||
size_t max = 0;
|
||||
|
||||
if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,[0-9]+\\}"))) {
|
||||
size_t separator = repeatStruct.find_first_of(',', 0);
|
||||
min = atoi(repeatStruct.substr(1, separator - 1).c_str());
|
||||
max = atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).c_str());
|
||||
}
|
||||
else if (boost::regex_match(repeatStruct, boost::regex("\\{,[0-9]+\\}"))) {
|
||||
size_t separator = repeatStruct.find_first_of(',', 0);
|
||||
min = 0;
|
||||
max = atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).c_str());
|
||||
}
|
||||
else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,\\}"))) {
|
||||
size_t separator = repeatStruct.find_first_of(',', 0);
|
||||
min = atoi(repeatStruct.substr(1, separator).c_str());
|
||||
max = MAX_REPETITIONS;
|
||||
}
|
||||
else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+\\}"))) {
|
||||
min = atoi(repeatStruct.substr(1, rsSize - 1).c_str());
|
||||
max = min;
|
||||
}
|
||||
else
|
||||
throw Error("Error: RegexRepeatMatcher.ParseRepetition(): Unrecognized format " + m_expr);
|
||||
|
||||
if (min > MAX_REPETITIONS || max > MAX_REPETITIONS || min > max)
|
||||
throw Error("Error: RegexRepeatMatcher.ParseRepetition(): Wrong number " + m_expr);
|
||||
|
||||
m_repeatMin = min;
|
||||
m_repeatMax = max;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
RegexRepeatMatcher::recursiveMatch(size_t repeat, const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
ssize_t tried = len;
|
||||
shared_ptr<RegexMatcher> matcher = m_matchers[0];
|
||||
|
||||
if (0 < len && repeat >= m_repeatMax) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == len && repeat < m_repeatMin) {
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == len && repeat >= m_repeatMin) {
|
||||
return true;
|
||||
}
|
||||
|
||||
while (tried >= 0) {
|
||||
if (matcher->match(name, offset, tried) &&
|
||||
recursiveMatch(repeat + 1, name, offset + tried, len - tried))
|
||||
return true;
|
||||
tried--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#ifndef NDN_UTIL_REGEX_REGEX_REPEAT_MATCHER_HPP
|
||||
@@ -40,12 +38,10 @@ public:
|
||||
size_t indicator);
|
||||
|
||||
virtual
|
||||
~RegexRepeatMatcher()
|
||||
{
|
||||
}
|
||||
~RegexRepeatMatcher() NDN_CXX_DECL_FINAL;
|
||||
|
||||
virtual bool
|
||||
match(const Name& name, size_t offset, size_t len);
|
||||
match(const Name& name, size_t offset, size_t len) NDN_CXX_DECL_FINAL;
|
||||
|
||||
protected:
|
||||
/**
|
||||
@@ -53,7 +49,7 @@ protected:
|
||||
* @returns true if compiling succeeds
|
||||
*/
|
||||
virtual void
|
||||
compile();
|
||||
compile() NDN_CXX_DECL_FINAL;
|
||||
|
||||
private:
|
||||
bool
|
||||
@@ -70,166 +66,6 @@ private:
|
||||
size_t m_repeatMax;
|
||||
};
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#include "regex-backref-matcher.hpp"
|
||||
#include "regex-component-set-matcher.hpp"
|
||||
|
||||
namespace ndn {
|
||||
|
||||
inline
|
||||
RegexRepeatMatcher::RegexRepeatMatcher(const std::string& expr,
|
||||
shared_ptr<RegexBackrefManager> backrefManager,
|
||||
size_t indicator)
|
||||
: RegexMatcher(expr, EXPR_REPEAT_PATTERN, backrefManager)
|
||||
, m_indicator(indicator)
|
||||
{
|
||||
compile();
|
||||
}
|
||||
|
||||
inline void
|
||||
RegexRepeatMatcher::compile()
|
||||
{
|
||||
shared_ptr<RegexMatcher> matcher;
|
||||
|
||||
if ('(' == m_expr[0]) {
|
||||
matcher = make_shared<RegexBackrefMatcher>(m_expr.substr(0, m_indicator), m_backrefManager);
|
||||
m_backrefManager->pushRef(matcher);
|
||||
dynamic_pointer_cast<RegexBackrefMatcher>(matcher)->lateCompile();
|
||||
}
|
||||
else{
|
||||
matcher = make_shared<RegexComponentSetMatcher>(m_expr.substr(0, m_indicator),
|
||||
m_backrefManager);
|
||||
}
|
||||
m_matchers.push_back(matcher);
|
||||
|
||||
parseRepetition();
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegexRepeatMatcher::parseRepetition()
|
||||
{
|
||||
size_t exprSize = m_expr.size();
|
||||
const size_t MAX_REPETITIONS = std::numeric_limits<size_t>::max();
|
||||
|
||||
if (exprSize == m_indicator) {
|
||||
m_repeatMin = 1;
|
||||
m_repeatMax = 1;
|
||||
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (exprSize == (m_indicator + 1)) {
|
||||
if ('?' == m_expr[m_indicator]) {
|
||||
m_repeatMin = 0;
|
||||
m_repeatMax = 1;
|
||||
return true;
|
||||
}
|
||||
if ('+' == m_expr[m_indicator]) {
|
||||
m_repeatMin = 1;
|
||||
m_repeatMax = MAX_REPETITIONS;
|
||||
return true;
|
||||
}
|
||||
if ('*' == m_expr[m_indicator]) {
|
||||
m_repeatMin = 0;
|
||||
m_repeatMax = MAX_REPETITIONS;
|
||||
return true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
std::string repeatStruct = m_expr.substr(m_indicator, exprSize - m_indicator);
|
||||
size_t rsSize = repeatStruct.size();
|
||||
size_t min = 0;
|
||||
size_t max = 0;
|
||||
|
||||
if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,[0-9]+\\}"))) {
|
||||
size_t separator = repeatStruct.find_first_of(',', 0);
|
||||
min = atoi(repeatStruct.substr(1, separator - 1).c_str());
|
||||
max = atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).c_str());
|
||||
}
|
||||
else if (boost::regex_match(repeatStruct, boost::regex("\\{,[0-9]+\\}"))) {
|
||||
size_t separator = repeatStruct.find_first_of(',', 0);
|
||||
min = 0;
|
||||
max = atoi(repeatStruct.substr(separator + 1, rsSize - separator - 2).c_str());
|
||||
}
|
||||
else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+,\\}"))) {
|
||||
size_t separator = repeatStruct.find_first_of(',', 0);
|
||||
min = atoi(repeatStruct.substr(1, separator).c_str());
|
||||
max = MAX_REPETITIONS;
|
||||
}
|
||||
else if (boost::regex_match(repeatStruct, boost::regex("\\{[0-9]+\\}"))) {
|
||||
min = atoi(repeatStruct.substr(1, rsSize - 1).c_str());
|
||||
max = min;
|
||||
}
|
||||
else
|
||||
throw RegexMatcher::Error(std::string("Error: RegexRepeatMatcher.ParseRepetition(): ")
|
||||
+ "Unrecognized format "+ m_expr);
|
||||
|
||||
if (min > MAX_REPETITIONS || max > MAX_REPETITIONS || min > max)
|
||||
throw RegexMatcher::Error(std::string("Error: RegexRepeatMatcher.ParseRepetition(): ")
|
||||
+ "Wrong number " + m_expr);
|
||||
|
||||
m_repeatMin = min;
|
||||
m_repeatMax = max;
|
||||
|
||||
return true;
|
||||
}
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegexRepeatMatcher::match(const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
m_matchResult.clear();
|
||||
|
||||
if (0 == m_repeatMin)
|
||||
if (0 == len)
|
||||
return true;
|
||||
|
||||
if (recursiveMatch(0, name, offset, len))
|
||||
{
|
||||
for (size_t i = offset; i < offset + len; i++)
|
||||
m_matchResult.push_back(name.get(i));
|
||||
return true;
|
||||
}
|
||||
else
|
||||
return false;
|
||||
}
|
||||
|
||||
inline bool
|
||||
RegexRepeatMatcher::recursiveMatch(size_t repeat, const Name& name, size_t offset, size_t len)
|
||||
{
|
||||
ssize_t tried = len;
|
||||
shared_ptr<RegexMatcher> matcher = m_matchers[0];
|
||||
|
||||
if (0 < len && repeat >= m_repeatMax)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == len && repeat < m_repeatMin)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
if (0 == len && repeat >= m_repeatMin)
|
||||
{
|
||||
return true;
|
||||
}
|
||||
|
||||
while (tried >= 0)
|
||||
{
|
||||
if (matcher->match(name, offset, tried) &&
|
||||
recursiveMatch(repeat + 1, name, offset + tried, len - tried))
|
||||
return true;
|
||||
tried--;
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
|
||||
} // namespace ndn
|
||||
|
||||
#endif // NDN_UTIL_REGEX_REGEX_REPEAT_MATCHER_HPP
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#include "regex-top-matcher.hpp"
|
||||
@@ -47,8 +45,6 @@ RegexTopMatcher::~RegexTopMatcher()
|
||||
void
|
||||
RegexTopMatcher::compile()
|
||||
{
|
||||
std::string errMsg = "Error: RegexTopMatcher.Compile(): ";
|
||||
|
||||
std::string expr = m_expr;
|
||||
|
||||
if ('$' != expr[expr.size() - 1])
|
||||
@@ -78,21 +74,18 @@ RegexTopMatcher::match(const Name& name)
|
||||
|
||||
m_matchResult.clear();
|
||||
|
||||
if (m_primaryMatcher->match(name, 0, name.size()))
|
||||
{
|
||||
m_matchResult = m_primaryMatcher->getMatchResult();
|
||||
if (m_primaryMatcher->match(name, 0, name.size())) {
|
||||
m_matchResult = m_primaryMatcher->getMatchResult();
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
if (static_cast<bool>(m_secondaryMatcher) && m_secondaryMatcher->match(name, 0, name.size())) {
|
||||
m_matchResult = m_secondaryMatcher->getMatchResult();
|
||||
m_isSecondaryUsed = true;
|
||||
return true;
|
||||
}
|
||||
else
|
||||
{
|
||||
if (static_cast<bool>(m_secondaryMatcher) && m_secondaryMatcher->match(name, 0, name.size()))
|
||||
{
|
||||
m_matchResult = m_secondaryMatcher->getMatchResult();
|
||||
m_isSecondaryUsed = true;
|
||||
return true;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
@@ -106,7 +99,7 @@ RegexTopMatcher::expand(const std::string& expandStr)
|
||||
{
|
||||
Name result;
|
||||
|
||||
shared_ptr<RegexBackrefManager> backrefManager =
|
||||
auto backrefManager =
|
||||
(m_isSecondaryUsed ? m_secondaryBackrefManager : m_primaryBackrefManager);
|
||||
|
||||
size_t backrefNo = backrefManager->size();
|
||||
@@ -119,36 +112,32 @@ RegexTopMatcher::expand(const std::string& expandStr)
|
||||
expand = m_expand;
|
||||
|
||||
size_t offset = 0;
|
||||
while (offset < expand.size())
|
||||
{
|
||||
std::string item = getItemFromExpand(expand, offset);
|
||||
if (item[0] == '<')
|
||||
{
|
||||
result.append(item.substr(1, item.size() - 2));
|
||||
}
|
||||
if (item[0] == '\\')
|
||||
{
|
||||
size_t index = boost::lexical_cast<size_t>(item.substr(1, item.size() - 1));
|
||||
|
||||
if (0 == index) {
|
||||
std::vector<name::Component>::iterator it = m_matchResult.begin();
|
||||
std::vector<name::Component>::iterator end = m_matchResult.end();
|
||||
for (; it != end; it++)
|
||||
result.append(*it);
|
||||
}
|
||||
else if (index <= backrefNo)
|
||||
{
|
||||
std::vector<name::Component>::const_iterator it =
|
||||
backrefManager->getBackref(index - 1)->getMatchResult().begin();
|
||||
std::vector<name::Component>::const_iterator end =
|
||||
backrefManager->getBackref(index - 1)->getMatchResult().end();
|
||||
for (; it != end; it++)
|
||||
result.append(*it);
|
||||
}
|
||||
else
|
||||
throw RegexMatcher::Error("Exceed the range of back reference");
|
||||
}
|
||||
while (offset < expand.size()) {
|
||||
std::string item = getItemFromExpand(expand, offset);
|
||||
if (item[0] == '<') {
|
||||
result.append(item.substr(1, item.size() - 2));
|
||||
}
|
||||
if (item[0] == '\\') {
|
||||
size_t index = boost::lexical_cast<size_t>(item.substr(1, item.size() - 1));
|
||||
|
||||
if (0 == index) {
|
||||
std::vector<name::Component>::iterator it = m_matchResult.begin();
|
||||
std::vector<name::Component>::iterator end = m_matchResult.end();
|
||||
for (; it != end; it++)
|
||||
result.append(*it);
|
||||
}
|
||||
else if (index <= backrefNo) {
|
||||
std::vector<name::Component>::const_iterator it =
|
||||
backrefManager->getBackref(index - 1)->getMatchResult().begin();
|
||||
std::vector<name::Component>::const_iterator end =
|
||||
backrefManager->getBackref(index - 1)->getMatchResult().end();
|
||||
for (; it != end; it++)
|
||||
result.append(*it);
|
||||
}
|
||||
else
|
||||
throw Error("Exceed the range of back reference");
|
||||
}
|
||||
}
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -157,44 +146,41 @@ RegexTopMatcher::getItemFromExpand(const std::string& expand, size_t& offset)
|
||||
{
|
||||
size_t begin = offset;
|
||||
|
||||
if (expand[offset] == '\\')
|
||||
{
|
||||
offset++;
|
||||
if (offset >= expand.size())
|
||||
throw RegexMatcher::Error("wrong format of expand string!");
|
||||
if (expand[offset] == '\\') {
|
||||
offset++;
|
||||
if (offset >= expand.size())
|
||||
throw Error("wrong format of expand string!");
|
||||
|
||||
while (expand[offset] <= '9' and expand[offset] >= '0') {
|
||||
offset++;
|
||||
if (offset > expand.size())
|
||||
throw RegexMatcher::Error("wrong format of expand string!");
|
||||
}
|
||||
if (offset > begin + 1)
|
||||
return expand.substr(begin, offset - begin);
|
||||
else
|
||||
throw RegexMatcher::Error("wrong format of expand string!");
|
||||
while (expand[offset] <= '9' and expand[offset] >= '0') {
|
||||
offset++;
|
||||
if (offset > expand.size())
|
||||
throw Error("wrong format of expand string!");
|
||||
}
|
||||
else if (expand[offset] == '<')
|
||||
{
|
||||
offset++;
|
||||
if (offset >= expand.size())
|
||||
throw RegexMatcher::Error("wrong format of expand string!");
|
||||
|
||||
size_t left = 1;
|
||||
size_t right = 0;
|
||||
while (right < left)
|
||||
{
|
||||
if (expand[offset] == '<')
|
||||
left++;
|
||||
if (expand[offset] == '>')
|
||||
right++;
|
||||
offset++;
|
||||
if (offset >= expand.size())
|
||||
throw RegexMatcher::Error("wrong format of expand string!");
|
||||
}
|
||||
if (offset > begin + 1)
|
||||
return expand.substr(begin, offset - begin);
|
||||
else
|
||||
throw Error("wrong format of expand string!");
|
||||
}
|
||||
else if (expand[offset] == '<') {
|
||||
offset++;
|
||||
if (offset >= expand.size())
|
||||
throw Error("wrong format of expand string!");
|
||||
|
||||
size_t left = 1;
|
||||
size_t right = 0;
|
||||
while (right < left) {
|
||||
if (expand[offset] == '<')
|
||||
left++;
|
||||
if (expand[offset] == '>')
|
||||
right++;
|
||||
offset++;
|
||||
if (offset >= expand.size())
|
||||
throw Error("wrong format of expand string!");
|
||||
}
|
||||
return expand.substr(begin, offset - begin);
|
||||
}
|
||||
else
|
||||
throw RegexMatcher::Error("wrong format of expand string!");
|
||||
throw Error("wrong format of expand string!");
|
||||
}
|
||||
|
||||
shared_ptr<RegexTopMatcher>
|
||||
@@ -202,12 +188,11 @@ RegexTopMatcher::fromName(const Name& name, bool hasAnchor)
|
||||
{
|
||||
std::string regexStr("^");
|
||||
|
||||
for (Name::const_iterator it = name.begin(); it != name.end(); it++)
|
||||
{
|
||||
regexStr.append("<");
|
||||
regexStr.append(convertSpecialChar(it->toUri()));
|
||||
regexStr.append(">");
|
||||
}
|
||||
for (const auto& comp : name) {
|
||||
regexStr.append("<");
|
||||
regexStr.append(convertSpecialChar(comp.toUri()));
|
||||
regexStr.append(">");
|
||||
}
|
||||
|
||||
if (hasAnchor)
|
||||
regexStr.append("$");
|
||||
@@ -221,31 +206,30 @@ std::string
|
||||
RegexTopMatcher::convertSpecialChar(const std::string& str)
|
||||
{
|
||||
std::string newStr;
|
||||
for (size_t i = 0; i < str.size(); i++)
|
||||
{
|
||||
char c = str[i];
|
||||
switch (c)
|
||||
{
|
||||
case '.':
|
||||
case '[':
|
||||
case '{':
|
||||
case '}':
|
||||
case '(':
|
||||
case ')':
|
||||
case '\\':
|
||||
case '*':
|
||||
case '+':
|
||||
case '?':
|
||||
case '|':
|
||||
case '^':
|
||||
case '$':
|
||||
newStr.push_back('\\');
|
||||
// Fallthrough
|
||||
default:
|
||||
newStr.push_back(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
for (size_t i = 0; i < str.size(); i++) {
|
||||
char c = str[i];
|
||||
switch (c)
|
||||
{
|
||||
case '.':
|
||||
case '[':
|
||||
case '{':
|
||||
case '}':
|
||||
case '(':
|
||||
case ')':
|
||||
case '\\':
|
||||
case '*':
|
||||
case '+':
|
||||
case '?':
|
||||
case '|':
|
||||
case '^':
|
||||
case '$':
|
||||
newStr.push_back('\\');
|
||||
// Fallthrough
|
||||
default:
|
||||
newStr.push_back(c);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
return newStr;
|
||||
}
|
||||
|
||||
@@ -1,6 +1,6 @@
|
||||
/* -*- Mode:C++; c-file-style:"gnu"; indent-tabs-mode:nil; -*- */
|
||||
/**
|
||||
* Copyright (c) 2013-2014 Regents of the University of California.
|
||||
* Copyright (c) 2013-2015 Regents of the University of California.
|
||||
*
|
||||
* This file is part of ndn-cxx library (NDN C++ library with eXperimental eXtensions).
|
||||
*
|
||||
@@ -17,8 +17,6 @@
|
||||
* <http://www.gnu.org/licenses/>.
|
||||
*
|
||||
* See AUTHORS.md for complete list of ndn-cxx authors and contributors.
|
||||
*
|
||||
* @author Yingdi Yu <http://irl.cs.ucla.edu/~yingdi/>
|
||||
*/
|
||||
|
||||
#ifndef NDN_UTIL_REGEX_REGEX_TOP_MATCHER_HPP
|
||||
@@ -39,13 +37,13 @@ public:
|
||||
RegexTopMatcher(const std::string& expr, const std::string& expand = "");
|
||||
|
||||
virtual
|
||||
~RegexTopMatcher();
|
||||
~RegexTopMatcher() NDN_CXX_DECL_FINAL;
|
||||
|
||||
bool
|
||||
match(const Name& name);
|
||||
|
||||
virtual bool
|
||||
match(const Name& name, size_t offset, size_t len);
|
||||
match(const Name& name, size_t offset, size_t len) NDN_CXX_DECL_FINAL;
|
||||
|
||||
virtual Name
|
||||
expand(const std::string& expand = "");
|
||||
@@ -55,7 +53,7 @@ public:
|
||||
|
||||
protected:
|
||||
virtual void
|
||||
compile();
|
||||
compile() NDN_CXX_DECL_FINAL;
|
||||
|
||||
private:
|
||||
std::string
|
||||
|
||||
Reference in new issue
Block a user