PyNDN: Bug fixing and API unification
diff --git a/PyNDN/Data.py b/PyNDN/Data.py
index 99a3d07..5165d2c 100644
--- a/PyNDN/Data.py
+++ b/PyNDN/Data.py
@@ -19,6 +19,7 @@
import ns.ndnSIM
from Name import Name
+from SignedInfo import SignedInfo
class DataError (Exception):
pass
@@ -30,14 +31,14 @@
name = None, content = None, signed_info = None,
data = None):
if data:
- if type (data) is Data:
+ if isinstance (data, Data):
self._data = data._data
- elif type (data) is ns.ndnSIM.ndn.ContentObject:
+ elif isinstance (data, ns.ndnSIM.ndn.Data):
self._data = data
else:
raise TypeError ("Invalid type supplied for 'data' parameter [%s]" % type (data))
else:
- self._data = ns.ndnSIM.ndn.ContentObject ()
+ self._data = ns.ndnSIM.ndn.Data ()
self.name = name
self.content = content
@@ -88,9 +89,9 @@
return object.__setattr__ (self, name, value)
elif name == 'signedInfo':
- if not value:
+ if value is None:
return
- if type (value) is SignedInfo:
+ if isinstance (value, SignedInfo):
object.__setattr__ (self, name, value)
if value.timestamp:
@@ -103,18 +104,18 @@
else:
raise TypeError ("signedInfo can be assigned either None or SignedInfo object, [%s] supplied" % type (value))
elif name == "name":
- if not value:
+ if value is None:
return self._data.SetName (ns.ndnSIM.ndn.Name ())
- elif type (value) is Name:
+ elif isinstance (value, Name):
return self._data.SetName (value._name)
- elif type (value) is ns.ndnSIM.ndn.Name:
+ elif isinstance (value, ns.ndnSIM.ndn.Name):
return self._data.SetName (value)
- elif type (value) is str:
+ elif isinstance (value, str):
return self._data.SetName (ns.ndnSIM.ndn.Name (value))
else:
raise ValueError ("Invalid name parameter")
elif name == "content":
- if not value:
+ if value is None:
pkt = ns.network.Packet ()
self._data.SetPayload (pkt)
else:
@@ -125,27 +126,3 @@
def __repr__(self):
return "ndn.Data(%s)" % str (self._data)
-
-class SignedInfo (object):
- def __init__(self, keyLocator = None, freshness = None, timestamp = None):
-
- self.timestamp = timestamp
- self.freshnessSeconds = freshness
- self.keyLocator = keyLocator
-
- def __repr__(self):
- args = []
-
- if self.keyLocator is not None:
- args += ["keyLocator=%r" % self.keyLocator]
- if self.freshnessSeconds is not None:
- args += ["freshness=%r" % self.freshnessSeconds]
- if self.timeStamp is not None:
- args += ["timestamp=%r" % self.timestamp]
-
- return "ndn.SignedInfo(%s)" % ", ".join(args)
-
-class ContentObject (Data):
- """For backwards compatibility"""
- pass
-
diff --git a/PyNDN/EventLoop.py b/PyNDN/EventLoop.py
new file mode 100644
index 0000000..93bd8e7
--- /dev/null
+++ b/PyNDN/EventLoop.py
@@ -0,0 +1,37 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# Alexander Afanasyev
+#
+# GNU 3.0 license, See the LICENSE file for more information
+#
+# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+#
+
+#
+# Based on PyCCN code, copyrighted and licensed as follows
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# BSD license, See the COPYING file for more information
+# Written by: Derek Kulinski <takeda@takeda.tk>
+# Jeff Burke <jburke@ucla.edu>
+#
+
+import ns.core
+
+class EventLoop (object):
+ """
+ Class to provide compatibility with real PyNDN implementation.
+ """
+
+ def __init__ (self, *handlers):
+ pass
+
+ def execute (self, event):
+ ns.core.Simulator.ScheduleNow (event)
+
+ def run (self):
+ pass
+
+ def stop (self):
+ pass
diff --git a/PyNDN/Face.py b/PyNDN/Face.py
index 6186569..3f76f5d 100644
--- a/PyNDN/Face.py
+++ b/PyNDN/Face.py
@@ -1,12 +1,12 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-#
+#
# Copyright (c) 2011-2013, Regents of the University of California
# Alexander Afanasyev
-#
+#
# GNU 3.0 license, See the LICENSE file for more information
-#
+#
# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
-#
+#
#
# Based on PyCCN code, copyrighted and licensed as follows
@@ -22,6 +22,7 @@
import ns.ndnSIM
from Data import Data
from Interest import Interest
+from Name import Name
import functools
@@ -40,7 +41,7 @@
def defer_verification (self, deferVerification = True):
pass
- def expressInterestSimple (self, name, onData, onTimeout, template = None):
+ def expressInterest (self, name, onData, onTimeout, template = None):
"""
onData: void <interest, name>
onTimeout: void <interest>
@@ -55,7 +56,7 @@
def __call__ (self, interest, data):
if self.onData:
return self.onData (Interest (interest=interest), Data (data = data))
-
+
class OnTimeoutConvert:
def __init__ (self, onTimeout):
self.onTimeout = onTimeout
@@ -63,9 +64,9 @@
if self.onTimeout:
self.onTimeout (Interest (interest=interest))
- self.ExpressInterest (interest, OnDataConvert (onData), OnTimeoutConvert (onTimeout))
+ self.ExpressInterest (interest._interest, OnDataConvert (onData), OnTimeoutConvert (onTimeout))
- def setInterestFilterSimple (self, name, onInterest, flags = None):
+ def setInterestFilter (self, name, onInterest, flags = None):
"""
onInterest: void <name, interest>
"""
@@ -77,27 +78,27 @@
if self.onInterest:
self.onInterest (Name (name = name), Interest (interest = interest))
+ if isinstance (name, Name):
+ name = name._name
+ elif isinstance (name, ns.ndnSIM.ndn.Name):
+ pass
+ else:
+ raise TypeError ("Wrong type for 'name' parameter [%s]" % type (name))
+
self.SetInterestFilter (name, OnInterestConvert (onInterest))
def clearInterestFilter (self, name):
- if type (name) is Name:
- self.ClearInterestFilter (name._name)
- elif type (name) is ns.ndnSIM.ndn.Name:
- self.ClearInterestFilter (name)
+ if isinstance (name, Name):
+ name = name._name
+ elif isinstance (name, ns.ndnSIM.ndn.Name):
+ pass
else:
raise TypeError ("Wrong type for 'name' parameter [%s]" % type (name))
+ self.ClearInterestFilter (name)
+
def get (self, name, template = None, timeoutms = 3000):
raise NotImplementedError ("NS-3 simulation cannot have syncrhonous operations")
def put (self, data):
self.Put (data)
-
-class EventLoop(object):
- def execute (self, event):
- ns.core.Simulator.ScheduleNow (event)
-
- def run (self, timeoutMs):
- ns.core.Simulator.Stop (ns.core.MilliSeconds (timeoutMs))
- ns.core.Simulator.Run ()
- ns.core.Simulator.Destroy ()
diff --git a/PyNDN/Interest.py b/PyNDN/Interest.py
index 571bc36..b4b5b9a 100644
--- a/PyNDN/Interest.py
+++ b/PyNDN/Interest.py
@@ -28,9 +28,9 @@
name = None, scope = None, interestLifetime = None,
interest = None):
if interest:
- if type (interest) is Interest:
+ if isinstance (interest, Interest):
self._interest = interest._interest
- elif type (interest) is ns.ndnSIM.ndn.Interest:
+ elif isinstance (interest, ns.ndnSIM.ndn.Interest):
self._interest = interest
else:
raise TypeError ("Invalid type supplied for 'interest' parameter [%s]" % type (interest))
@@ -66,27 +66,27 @@
return object.__setattr__ (self, name, value)
elif name == "name":
- if not value:
+ if value is None:
return self._interest.SetName (ns.ndnSIM.ndn.Name ())
- elif type (value) is Name:
+ elif isinstance (value, Name):
return self._interest.SetName (value._name)
- elif type (value) is ns.ndnSIM.ndn.Name:
+ elif isinstance (value, ns.ndnSIM.ndn.Name):
return self._interest.SetName (value)
- elif type (value) is str:
+ elif isinstance (value, str):
return self._interest.SetName (ns.ndnSIM.ndn.Name (value))
else:
raise ValueError ("Invalid name parameter")
elif name == "scope":
- if not value:
+ if value is None:
return self._interest.SetScope (-1)
- elif type (value) is int:
+ elif isinstance (value, int):
return self._interest.SetScope (value)
else:
raise ValueError ("Scope parameter should be int, [%s] supplied" % type (value))
elif name == "interestLifetime":
- if not value:
+ if value is None:
return self._interest.SetInterestLifetime (ns.core.Time ())
- elif type (value) is float or type (value) is int:
+ elif isinstance (value, float) or isinstance (value, int):
return self._interest.SetInterestLifetime (ns.core.Seconds (value))
else:
raise ValueError ("interestLifetime parameter should be fload or int, [%s] supplied" % type (value))
diff --git a/PyNDN/Key.py b/PyNDN/Key.py
index b5c065b..2dc562a 100644
--- a/PyNDN/Key.py
+++ b/PyNDN/Key.py
@@ -21,7 +21,7 @@
import ns.ndnSIM
from Name import Name
-class Key(object):
+class Key (object):
def __init__ (self):
# self.publicKeyID = None # SHA256 hash
self.fakeKey = None
@@ -81,18 +81,3 @@
key = Key ()
key.fakeKey = context
return key
-
-
-class KeyLocator(object):
- def __init__(self, keyName = None):
- self.keyName = keyName
-
- @staticmethod
- def getDefaultKeyLocator():
- context = ns.core.Simulator.GetContext ()
- keyLocator = ns.ndnSIM.ndn.Name ()
- keyLocator.\
- append ("default-key").\
- append (str (context))
-
- return Name (keyLocator)
diff --git a/PyNDN/KeyLocator.py b/PyNDN/KeyLocator.py
new file mode 100644
index 0000000..331ae63
--- /dev/null
+++ b/PyNDN/KeyLocator.py
@@ -0,0 +1,36 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# Alexander Afanasyev
+#
+# GNU 3.0 license, See the LICENSE file for more information
+#
+# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+#
+
+#
+# Based on PyCCN code, copyrighted and licensed as follows
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# BSD license, See the COPYING file for more information
+# Written by: Derek Kulinski <takeda@takeda.tk>
+# Jeff Burke <jburke@ucla.edu>
+#
+
+import ns.core
+import ns.ndnSIM
+from Name import Name
+
+class KeyLocator (object):
+ def __init__(self, keyName = None):
+ self.keyName = keyName
+
+ @staticmethod
+ def getDefaultKeyLocator():
+ context = ns.core.Simulator.GetContext ()
+ keyLocator = ns.ndnSIM.ndn.Name ()
+ keyLocator.\
+ append ("default-key").\
+ append (str (context))
+
+ return Name (keyLocator)
diff --git a/PyNDN/Name.py b/PyNDN/Name.py
index 05c34b0..7729a25 100644
--- a/PyNDN/Name.py
+++ b/PyNDN/Name.py
@@ -19,16 +19,16 @@
import ns.ndnSIM
-class Name ():
+class Name (object):
_name = None
def __init__ (self,
value = None,
name = None):
if name:
- if type (name) is ns.ndnSIM.ndn.Name:
+ if isinstance (name, ns.ndnSIM.ndn.Name):
self._name = name
- elif type (name) is Name:
+ elif isinstance (name, Name):
self._name = name._name
else:
raise TypeError ("Incorrect type for 'name' parameter [%s]" % type (name))
@@ -44,6 +44,10 @@
def toWire (self):
return ns.ndnSIM.ndn.Wire.FromName (self._name)
+
+ def append (self, value):
+ self._name.append (value)
+ return self
def __getattr__ (self, name):
return self._name.__getattribute__ (name)
@@ -55,12 +59,12 @@
return self._name.append (other)
def __getitem__(self, key):
- if type (key) is int:
+ if isinstance (key, int):
if abs(key) < self._name.size ():
return self._name.get (key)
else:
raise IndexError ("index out of range")
- elif type (key) is slice:
+ elif isinstance (key, slice):
name = ns.ndnSIM.ndn.Name ()
for component in xrange (*key.indices (self.size ())):
name.append (self._name.get (component))
@@ -71,3 +75,5 @@
def __repr__ (self):
return "ndnSIM.Name('" + self._name.toUri () + "')"
+ def __str__ (self):
+ return self._name.toUri ()
diff --git a/PyNDN/SignedInfo.py b/PyNDN/SignedInfo.py
new file mode 100644
index 0000000..79c2f4f
--- /dev/null
+++ b/PyNDN/SignedInfo.py
@@ -0,0 +1,53 @@
+## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# Alexander Afanasyev
+#
+# GNU 3.0 license, See the LICENSE file for more information
+#
+# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+#
+
+#
+# Based on PyCCN code, copyrighted and licensed as follows
+#
+# Copyright (c) 2011-2013, Regents of the University of California
+# BSD license, See the COPYING file for more information
+# Written by: Derek Kulinski <takeda@takeda.tk>
+# Jeff Burke <jburke@ucla.edu>
+#
+
+import utils
+
+class ContentType(utils.Enum):
+ _prefix = "ndn"
+
+CONTENT_DATA = ContentType.new_flag('CONTENT_DATA', 0x0C04C0)
+CONTENT_ENCR = ContentType.new_flag('CONTENT_ENCR', 0x10D091)
+CONTENT_GONE = ContentType.new_flag('CONTENT_GONE', 0x18E344)
+CONTENT_KEY = ContentType.new_flag('CONTENT_KEY', 0x28463F)
+CONTENT_LINK = ContentType.new_flag('CONTENT_LINK', 0x2C834A)
+CONTENT_NACK = ContentType.new_flag('CONTENT_NACK', 0x34008A)
+
+class SignedInfo (object):
+ def __init__(self, keyLocator = None, freshness = None, timestamp = None, type = CONTENT_DATA):
+
+ self.timestamp = timestamp
+ self.freshnessSeconds = freshness
+ self.keyLocator = keyLocator
+ self.type = type
+
+ def __repr__(self):
+ args = []
+
+ if self.keyLocator is not None:
+ args += ["keyLocator=%r" % self.keyLocator]
+ if self.freshnessSeconds is not None:
+ args += ["freshness=%r" % self.freshnessSeconds]
+ if self.timeStamp is not None:
+ args += ["timestamp=%r" % self.timestamp]
+ if self.type != CONTENT_DATA:
+ args += ["type=%r" % self.type]
+
+ return "ndn.SignedInfo(%s)" % ", ".join(args)
+
diff --git a/PyNDN/__init__.py b/PyNDN/__init__.py
index 0c0e288..2054d49 100644
--- a/PyNDN/__init__.py
+++ b/PyNDN/__init__.py
@@ -1,12 +1,12 @@
## -*- Mode: python; py-indent-offset: 4; indent-tabs-mode: nil; coding: utf-8; -*-
-#
+#
# Copyright (c) 2011-2013, Regents of the University of California
# Alexander Afanasyev
-#
+#
# GNU 3.0 license, See the LICENSE file for more information
-#
+#
# Author: Alexander Afanasyev <alexander.afanasyev@ucla.edu>
-#
+#
#
# Based on PyCCN code, copyrighted and licensed as follows
@@ -17,7 +17,7 @@
# Jeff Burke <jburke@ucla.edu>
#
-__all__ = ['Face', 'Name', 'Interest', 'Data', 'Key', 'ContentObject']
+__all__ = ['Face', 'Name', 'Interest', 'Data', 'Key', 'EventLoop']
VERSION = 0.3
NDNSIM = True
@@ -25,12 +25,22 @@
import sys as _sys
try:
- from Face import Face, EventLoop
+ from Face import Face
from Name import Name
from Interest import Interest
- from Data import Data, ContentObject, SignedInfo
+ from Data import Data
from Key import Key
+ from EventLoop import EventLoop
+ from KeyLocator import KeyLocator
+ from SignedInfo import SignedInfo, CONTENT_DATA, CONTENT_ENCR, CONTENT_GONE, CONTENT_KEY, CONTENT_LINK, CONTENT_NACK
+ # no signature
+
+ # no NameCrypto
+ # no LocalPrefixDiscovery
+
+ import nre
+
except ImportError:
del _sys.modules[__name__]
raise
diff --git a/PyNDN/impl/segmenting.py b/PyNDN/impl/segmenting.py
index fb2d253..d58b200 100644
--- a/PyNDN/impl/segmenting.py
+++ b/PyNDN/impl/segmenting.py
@@ -32,7 +32,7 @@
name = self.name + ndn.Name.num2seg(segment)
self.signed_info.finalBlockID = ndn.Name.num2seg(segments - 1)
- co = ndn.ContentObject(name = name, content = chunk, signed_info = self.signed_info)
+ co = ndn.Data(name = name, content = chunk, signed_info = self.signed_info)
co.sign(self.key)
return co
diff --git a/PyNDN/nre.py b/PyNDN/nre.py
new file mode 100644
index 0000000..669a712
--- /dev/null
+++ b/PyNDN/nre.py
@@ -0,0 +1,631 @@
+# -*- Mode:python; c-file-style:"gnu"; indent-tabs-mode:nil -*- */
+#
+# Copyright (c) 2013, Regents of the University of California
+# Yingdi Yu, Alexander Afanasyev
+#
+# BSD license, See the doc/LICENSE file for more information
+#
+# Author: Yingdi Yu <yingdi@cs.ucla.edu>
+# Alexander Afanasyev <alexander.afanasyev@ucla.edu>
+#
+
+import sys
+import re
+import logging
+from Name import Name
+
+_LOG = logging.getLogger ("ndn.nre")
+
+class RegexError(Exception):
+ def __init__(self, msg):
+ self.msg = msg
+ def __str__(self):
+ return self.msg
+
+class BaseMatcher(object):
+ def __init__(self, expr, backRef, exact=True):
+ _LOG.debug(self.__class__.__name__ + ".Constructor")
+ self.expr = expr
+ self.backRef = backRef
+ self.exact = exact
+ self.matchResult = []
+ self.matcherList = []
+
+ def match(self, name, offset, len):
+ _LOG.debug(self.__class__.__name__ + ".match(): " + "expr: " + self.expr + " offset: " + str(offset) + " length: " + str(len))
+ self.matchResult = []
+
+ if self._recursiveMatch(0, name, offset, len):
+ for i in range(offset, offset + len):
+ self.matchResult.append(name[i])
+ return True
+ else:
+ return False
+
+ def _recursiveMatch(self, mId, name, offset, length):
+ _LOG.debug(self.__class__.__name__ + "._recursiveMatch(): " + self.expr)
+ _LOG.debug("mId: " + str(mId) + " name: " + str(name) + " offset: " + str(offset) + " length: " + str(length) + " matcherListSize: " + str(len(self.matcherList)))
+ tried = 0
+
+ if mId >= len(self.matcherList) :
+ if length != 0 :
+ _LOG.debug("Fail " + self.__class__.__name__ + "._recursiveMatch(): no more matcher, but more components")
+ return False
+ else:
+ _LOG.debug("Succeed " + self.__class__.__name__ + "._recursiveMatch(): no more matcher, no more components")
+ return True
+
+ matcher = self.matcherList[mId]
+
+ while tried <= length:
+ if matcher.match(name, offset, tried) and self._recursiveMatch(mId + 1, name, offset + tried, length - tried) :
+ return True
+ _LOG.debug(self.__class__.__name__ + " expr: " + self.expr + " mId: " + str(mId) + " tried: " + str(tried) + " length: " + str(length))
+ tried += 1
+
+ return False
+
+
+ def aggressiveMatch(self, name, offset, len):
+ _LOG.debug(self.__class__.__name__ + ".aggressiveMatch(): " + "expr: " + self.expr + " offset: " + str(offset) + " length: " + str(len))
+ self.matchResult = []
+
+ if self._aRecursiveMatch(0, name, offset, len):
+ for i in range(offset, offset + len):
+ self.matchResult.append(name[i])
+ return True
+ else:
+ return False
+
+ def _aRecursiveMatch(self, mId, name, offset, length):
+ _LOG.debug(self.__class__.__name__ + "._aRecursiveMatch(): " + self.expr)
+ _LOG.debug("mId: " + str(mId) + " name: " + str(name) + " offset: " + str(offset) + " length: " + str(length) + " matcherListSize: " + str(len(self.matcherList)))
+
+ tried = length
+
+ if mId >= len(self.matcherList) :
+ if length != 0 :
+ _LOG.debug("Fail " + self.__class__.__name__ + "._recursiveMatch(): no more matcher, but more components")
+ return False
+ else:
+ _LOG.debug("Succeed " + self.__class__.__name__ + "._recursiveMatch(): no more matcher, no more components")
+ return True
+
+ matcher = self.matcherList[mId]
+
+ while tried >= 0:
+ if matcher.aggressiveMatch(name, offset, tried) and self._aRecursiveMatch(mId + 1, name, offset + tried, length - tried):
+ return True
+ _LOG.debug(self.__class__.__name__ + " expr: " + self.expr + " mId: " + str(mId) + " tried: " + str(tried) + " length: " + str(length))
+ tried -= 1
+
+ return False
+
+
+class ComponentMatcher(BaseMatcher):
+ def __init__(self, expr, backRef, exact=True):
+ _LOG.debug(self.__class__.__name__ + ".Constructor")
+ _LOG.debug("expr " + expr)
+
+ super(ComponentMatcher, self).__init__(expr, backRef, exact)
+
+ pattern = re.compile(self.expr)
+ self.pseudoBackRefMatcher = []
+ for i in range(0, pattern.groups):
+ pseudoMatcher = BaseMatcher("", self.backRef)
+ self.pseudoBackRefMatcher.append(pseudoMatcher)
+ self.backRef.append(pseudoMatcher)
+
+ def _appendBackRef(self, res):
+ if res and 0 < len(res.groups()):
+
+ group = res.groups()
+ for i in range(0, len(group)):
+ self.pseudoBackRefMatcher[i].matchResult = []
+ self.pseudoBackRefMatcher[i].matchResult.append(group[i])
+
+ def match(self, name, offset, len):
+ _LOG.debug(self.__class__.__name__ + ".match(): " + self.expr)
+ _LOG.debug("Name " + str(name) + " offset " + str(offset) + " len " +str(len))
+
+ self.matchResult = []
+
+ if "" == self.expr:
+ res = self.matchResult.append(name[offset])
+ self._appendBackRef(res)
+ _LOG.debug("Succeed " + self.__class__.__name__ + ".match() ")
+ return True
+
+ matcher = re.compile(self.expr)
+ if self.exact:
+ res = matcher.match(name[offset])
+ if res:
+ self._appendBackRef(res)
+ self.matchResult.append(name[offset])
+ _LOG.debug("Succeed " + self.__class__.__name__ + ".match() ")
+ return True
+ else:
+ res = matcher.search(name[offset])
+ if res:
+ self._appendBackRef(res)
+ self.matchResult.append(name[offset])
+ return True
+
+ return False
+
+ def aggressiveMatch(self, name, offset, len):
+ return self.match(name, offset, len)
+
+
+class ComponentSetMatcher(BaseMatcher):
+ def __init__(self, expr, backRef, exact=True):
+ _LOG.debug(self.__class__.__name__ + ".Constructor")
+
+ errMsg = "Error: ComponentSetMatcher.Constructor: "
+ self.include = True
+
+ super(ComponentSetMatcher, self).__init__(expr, backRef, exact)
+
+ if '<' == self.expr[0]:
+ self._compileSingleComponent()
+ elif '[' == self.expr[0]:
+ lastIndex = len(self.expr) - 1
+ if ']' != self.expr[lastIndex]:
+ raise RegexError(errMsg + " No matched ']' " + self.expr)
+ if '^' == self.expr[1]:
+ self.include = False
+
+ self._compileMultipleComponents(2, lastIndex)
+ else:
+ self._compileMultipleComponents(1, lastIndex)
+
+
+ def _compileSingleComponent(self):
+ _LOG.debug(self.__class__.__name__ + "._compileSingleComponent")
+
+ errMsg = "Error: ComponentSetMatcher.CompileSingleComponent(): "
+
+ end = self._extractComponent(1)
+
+ if len(self.expr) != end:
+ raise RegexError(errMsg + "out of bound " + self.expr)
+ else:
+ self.matcherList.append(ComponentMatcher(self.expr[1:end-1], self.backRef))
+
+ def _compileMultipleComponents(self, start, lastIndex):
+ _LOG.debug(self.__class__.__name__ + "._compileMultipleComponents")
+
+ errMsg = "Error: ComponentSetMatcher.CompileMultipleComponents(): "
+
+ index = start
+ tmp_index = start
+
+ while index < lastIndex:
+ if '<' != self.expr[index]:
+ raise RegexError(errMsg + "Component expr error " + self.expr)
+ tmp_index = index + 1
+ index = self._extractComponent(tmp_index)
+ self.matcherList.append(ComponentMatcher(self.expr[tmp_index:index-1], self.backRef))
+
+ if index != lastIndex:
+ raise RegexError(errMsg + "Not sufficient expr to parse " + self.expr)
+
+ def _extractComponent(self, index):
+ _LOG.debug(self.__class__.__name__ + "._extractComponent")
+ lcount = 1
+ rcount = 0
+
+ while lcount > rcount :
+ if len(self.expr) == index:
+ break
+ elif '<' == self.expr[index]:
+ lcount += 1
+ elif '>' == self.expr[index]:
+ rcount += 1
+
+ index += 1
+
+ return index
+
+ def match(self, name, offset, len):
+ _LOG.debug(self.__class__.__name__ + ".match(): " + self.expr)
+
+ self.matchResult = []
+
+ matched = False
+
+ if 1 != len:
+ return False
+
+ for matcher in self.matcherList:
+ res = matcher.match(name, offset, len)
+ if True == res:
+ matched = True
+ break
+
+ if(matched if self.include else (not matched)):
+ self.matchResult.append(name[offset])
+ return True
+ else:
+ return False
+
+ def aggressiveMatch(self, name, offset, len):
+ return self.match(name, offset, len)
+
+class BackRefMatcher(BaseMatcher):
+ def __init__(self, expr, backRef, exact=True):
+ _LOG.debug (self.__class__.__name__ + ".Constructor")
+ super(BackRefMatcher, self).__init__(expr, backRef, exact)
+
+ errMsg = "Error: BackRefMatcher Constructor: "
+
+ _LOG.debug ("expr: " + self.expr);
+ _LOG.debug ("backRefManager " + str(self.backRef) + " size: " + str(len(self.backRef)))
+
+ lastIndex = len(self.expr) - 1
+
+ if '(' == self.expr[0] and ')' == self.expr[lastIndex]:
+ self.backRef.append(self)
+ self.matcherList.append(PatternListMatcher(self.expr[1:lastIndex], self.backRef, self.exact))
+ else:
+ raise RegexError(errMsg + " Unrecognoized format " + self.expr)
+
+
+class PatternListMatcher(BaseMatcher):
+ def __init__(self, expr, backRef, exact=True):
+ _LOG.debug(self.__class__.__name__ + ".Constructor")
+ super(PatternListMatcher, self).__init__(expr, backRef, exact)
+ _LOG.debug("expr: " + self.expr)
+
+ exprSize = len(self.expr)
+ index = 0
+ subHead = index
+
+ while index < exprSize:
+ subHead = index
+ (r_res, r_index) = self._extractPattern(subHead, index)
+ index = r_index
+ if not r_res:
+ raise RegexError("Fail to create PatternListMatcher")
+
+
+ def _extractPattern(self, index, next):
+ _LOG.debug(self.__class__.__name__ + "._extractPattern")
+
+ errMsg = "Error: PatternListMatcher._extractPattern: "
+
+ start = index
+ End = index
+ indicator = index
+
+ _LOG.debug ("expr: " + self.expr + " index: " + str(index))
+
+ if '(' == self.expr[index]:
+ index += 1
+ index = self._extractSubPattern('(', ')', index)
+ indicator = index
+ end = self._extractRepetition(index)
+ if indicator == end:
+ self.matcherList.append(BackRefMatcher(self.expr[start:end], self.backRef, self.exact))
+ else:
+ self.matcherList.append(RepeatMatcher(self.expr[start:end], self.backRef, indicator-start, self.exact))
+ elif '<' == self.expr[index]:
+ index += 1
+ index = self._extractSubPattern('<', '>', index)
+ indicator = index
+ end = self._extractRepetition(index)
+ self.matcherList.append(RepeatMatcher(self.expr[start:end], self.backRef, indicator-start, self.exact))
+ _LOG.debug("start: " + str(start) + " end: " + str(end) + " indicator: " + str(indicator))
+ elif '[' == self.expr[index]:
+ index += 1
+ index = self._extractSubPattern('[', ']', index)
+ indicator = index
+ end = self._extractRepetition(index)
+ self.matcherList.append(RepeatMatcher(self.expr[start:end], self.backRef, indicator-start, self.exact))
+ _LOG.debug("start: " + str(start) + " end: " + str(end) + " indicator: " + str(indicator))
+ else:
+ raise RegexError(errMsg +"unexpected syntax")
+
+
+
+ return (True, end)
+
+ def _extractSubPattern(self, left, right, index):
+ _LOG.debug(self.__class__.__name__ + "._extractSubPattern")
+
+ lcount = 1
+ rcount = 0
+
+ while lcount > rcount:
+ if index >= len(self.expr):
+ raise RegexError("Error: parenthesis mismatch")
+ if left == self.expr[index]:
+ lcount += 1
+ if right == self.expr[index]:
+ rcount += 1
+ index += 1
+
+ return index
+
+ def _extractRepetition(self, index):
+ _LOG.debug(self.__class__.__name__ + "._extractRepetition")
+
+ exprSize = len(self.expr)
+
+ _LOG.debug("expr: " + self.expr + " index: " + str(index))
+
+ errMsg = "Error: PatternListMatcher._extractRepetition: "
+
+ if index == exprSize:
+ return index
+
+ if '+' == self.expr[index] or '?' == self.expr[index] or '*' == self.expr[index] :
+ index += 1
+ return index
+
+ if '{' == self.expr[index]:
+ while '}' != self.expr[index]:
+ index += 1
+ if index == exprSize:
+ break
+ if index == exprSize:
+ raise RegexError(errMsg + "Missing right brace bracket")
+ else:
+ index += 1
+ return index
+ else:
+ _LOG.debug ("return index: " + str(index))
+ return index
+
+class RepeatMatcher(BaseMatcher):
+ def __init__(self, expr, backRef, indicator, exact=True):
+ _LOG.debug(self.__class__.__name__ + ".Constructor")
+ _LOG.debug("expr: " + expr);
+ super(RepeatMatcher, self).__init__(expr, backRef, exact)
+ self.indicator = indicator
+ if '(' == self.expr[0]:
+ self.matcherList.append(BackRefMatcher(self.expr[0:self.indicator], self.backRef))
+ else:
+ self.matcherList.append(ComponentSetMatcher(self.expr[0:self.indicator], self.backRef))
+
+ self._parseRepetition()
+ _LOG.debug("repeatMin: " + str(self.repeatMin) + " repeatMax: " + str(self.repeatMax))
+
+ def _parseRepetition(self):
+ _LOG.debug(self.__class__.__name__ + "._parseRepetition")
+
+ errMsg = "Error: RepeatMatcher._parseRepetition(): ";
+
+ exprSize = len(self.expr)
+ intMax = sys.maxint
+
+ if exprSize == self.indicator:
+ self.repeatMin = 1
+ self.repeatMax = 1
+ return
+ else:
+ if exprSize == (self.indicator + 1):
+ if '?' == self.expr[self.indicator]:
+ self.repeatMin = 0
+ self.repeatMax = 1
+ if '+' == self.expr[self.indicator]:
+ self.repeatMin = 1
+ self.repeatMax = intMax
+ if '*' == self.expr[self.indicator]:
+ self.repeatMin = 0
+ self.repeatMax = intMax
+ return
+ else:
+ repeatStruct = self.expr[self.indicator:exprSize]
+ min = 0
+ max = 0
+
+ if re.match('{[0-9]+,[0-9]+}$', repeatStruct):
+ repeats = repeatStruct[1:-1].split(',')
+ min = int(repeats[0])
+ max = int(repeats[1])
+ elif re.match('{[0-9]+,}$', repeatStruct):
+ repeats = repeatStruct[1:-1].split(',')
+ min = int(repeats[0])
+ max = intMax
+ elif re.match('{,[0-9]+}$', repeatStruct):
+ repeats = repeatStruct[1:-1].split(',')
+ min = 0
+ max = int(repeats[1])
+ elif re.match('{[0-9]+}$', repeatStruct):
+ min = int(repeatStruct[1:- 1])
+ max = min;
+ else:
+ raise RegexError(errMsg + "Unrecognized format "+ self.expr);
+
+ if min > intMax or max > intMax or min > max:
+ raise RegexError(errMsg + "Wrong number " + self.expr);
+
+ self.repeatMin = min
+ self.repeatMax = max
+
+ def match(self, name, offset, len):
+ _LOG.debug(self.__class__.__name__ + ".match(): " + "expr: " + self.expr + " offset: " + str(offset) + " len: " + str(len) + " repeatMin: " + str(self.repeatMin))
+ self.matchResult = []
+
+ if 0 == self.repeatMin:
+ if 0 == len:
+ return True
+
+ if self._recursiveMatch(0, name, offset, len):
+ for i in range(offset, offset+len):
+ self.matchResult.append(name[i])
+ return True
+ else:
+ return False
+
+ def _recursiveMatch(self, repeat, name, offset, len):
+ _LOG.debug (self.__class__.__name__ + "._recursiveMatch()" + " repeat: " + str(repeat) + " offset: " + str(offset) + " len: " + str(len) + " rMin: " + str(self.repeatMin) + " rMax: " + str(self.repeatMax))
+ tried = 0
+ matcher = self.matcherList[0]
+
+ if 0 < len and repeat >= self.repeatMax:
+ _LOG.debug("Match Fail: Reach m_repeatMax && More components")
+ return False
+
+ if 0 == len and repeat < self.repeatMin:
+ _LOG.debug("Match Fail: No more components && have NOT reached m_repeatMin " + str(len) + ", " + str(self.repeatMin))
+ return False
+
+ if 0 == len and repeat >= self.repeatMin:
+ _LOG.debug("Match Succeed: No more components && reach m_repeatMin")
+ return True
+
+ while tried <= len:
+ _LOG.debug("Attempt tried: " + str(tried))
+
+ if matcher.match(name, offset, tried) and self._recursiveMatch(repeat + 1, name, offset + tried, len - tried):
+ return True;
+ _LOG.debug("Failed at tried: " + str(tried));
+ tried += 1
+
+ return False
+
+
+ def aggressiveMatch(self, name, offset, len):
+ _LOG.debug(self.__class__.__name__ + ".aggressiveMatch(): " + "expr: " + self.expr + " offset: " + str(offset) + " len: " + str(len) + " repeatMin: " + str(self.repeatMin))
+ self.matchResult = []
+
+ if 0 == self.repeatMin:
+ if 0 == len:
+ return True
+
+ if self._aRecursiveMatch(0, name, offset, len):
+ for i in range(offset, offset+len):
+ self.matchResult.append(name[i])
+ return True
+ else:
+ return False
+
+ def _aRecursiveMatch(self, repeat, name, offset, len):
+ _LOG.debug (self.__class__.__name__ + "._aRecursiveMatch()" + " repeat: " + str(repeat) + " offset: " + str(offset) + " len: " + str(len) + " rMin: " + str(self.repeatMin) + " rMax: " + str(self.repeatMax))
+ tried = len
+ matcher = self.matcherList[0]
+
+ if 0 < len and repeat >= self.repeatMax:
+ _LOG.debug("Match Fail: Reach m_repeatMax && More components")
+ return False
+
+ if 0 == len and repeat < self.repeatMin:
+ _LOG.debug("Match Fail: No more components && have NOT reached m_repeatMin " + str(len) + ", " + str(self.repeatMin))
+ return False
+
+ if 0 == len and repeat >= self.repeatMin:
+ _LOG.debug("Match Succeed: No more components && reach m_repeatMin")
+ return True
+
+ while tried >= 0:
+ _LOG.debug("Attempt tried: " + str(tried))
+
+ if matcher.aggressiveMatch(name, offset, tried) and self._aRecursiveMatch(repeat + 1, name, offset + tried, len - tried):
+ return True;
+ _LOG.debug("Failed at tried: " + str(tried));
+ tried -= 1
+
+ return False
+
+
+
+class RegexMatcher(BaseMatcher):
+ def __init__(self, expr, exact=True):
+ _LOG.debug(self.__class__.__name__ + ".Constructor")
+ super(RegexMatcher, self).__init__(expr, None, exact)
+
+ self.backRef = []
+ self.second_backRef = []
+
+ self.secondaryMatcher = None
+
+
+ errMsg = "Error: RegexTopMatcher Constructor: "
+ tmp_expr = self.expr
+
+ if '$' != tmp_expr[-1]:
+ tmp_expr = tmp_expr + "<.*>*";
+ else:
+ tmp_expr = tmp_expr[0:-1]
+
+ if '^' != tmp_expr[0]:
+ self.secondaryMatcher = PatternListMatcher("<.*>*" + tmp_expr, self.second_backRef, self.exact)
+ else:
+ tmp_expr = tmp_expr[1:]
+
+ _LOG.debug ("reconstructed expr " + tmp_expr);
+
+ self.primaryMatcher = PatternListMatcher(tmp_expr, self.backRef, self.exact)
+
+
+
+ def firstMatcher():
+ return None
+
+ def matchName(self, name):
+ _LOG.debug(self.__class__.__name__ + ".matchName")
+
+ self.secondaryUsed = False
+
+ res = self.primaryMatcher.match(name, 0, len(name))
+ self.matchResult += self.primaryMatcher.matchResult
+ if False == res and None != self.secondaryMatcher:
+ res = self.secondaryMatcher.match(name, 0, len(name))
+ self.matchResult += self.secondaryMatcher.matchResult
+ self.secondaryUsed = True
+ return res
+
+ def extract(self, rule):
+ _LOG.debug(self.__class__.__name__ + ".extract")
+
+ if not re.match('(\\\\[0-9]+)+$', rule):
+ raise RegexError("Wrong format of rule")
+
+ refs = rule.split('\\')
+ refs.pop(0)
+
+ backRef = self.backRef
+ if self.secondaryUsed:
+ backRef = self.second_backRef
+
+ result = []
+ for index in refs:
+ i = int(index) - 1
+
+ if len(backRef) <= i or 0 > i:
+ raise RegexError("Wrong back reference number!")
+
+ result += backRef[i].matchResult
+
+ return result
+
+ def matchN(self, name):
+ _LOG.debug(self.__class__.__name__ + ".matchN")
+
+ self.secondaryUsed = False
+
+ res = self.primaryMatcher.aggressiveMatch(name, 0, len(name))
+ self.matchResult += self.primaryMatcher.matchResult
+ if False == res and None != self.secondaryMatcher:
+ res = self.secondaryMatcher.aggressiveMatch(name, 0, len(name))
+ self.matchResult += self.secondaryMatcher.matchResult
+ self.secondaryUsed = True
+ return res
+
+ def expand (self, rule):
+ return self.extract (rule)
+
+def match (pattern, name, flags=0):
+ """
+ If zero or more characters at the beginning of string match the regular expression pattern, return a corresponding matches as a list. Return None if the string does not match the pattern.
+"""
+ if not isinstance (name, Name):
+ raise TypeError ("name is not ndn.Name type")
+
+ m = RegexMatcher (pattern)
+ res = m.matchN (Name (name))
+ if not res:
+ return None
+ return m
diff --git a/PyNDN/utils.py b/PyNDN/utils.py
index 7cfe514..555ce80 100644
--- a/PyNDN/utils.py
+++ b/PyNDN/utils.py
@@ -96,3 +96,38 @@
inttime = int(value * 4096 + 0.5)
bintime = struct.pack("!Q", inttime)
return bintime.lstrip(b'\x00')
+
+class Const (object):
+ def __init__ (self, obj):
+ object.__setattr__ (self, "__internal_object", obj)
+ object.__setattr__ (self, "__bases__", type(obj))
+
+ def __getattribute__ (self, name):
+ if name != "__bases__":
+ return object.__getattribute__ (self, "__internal_object").__getattribute__ (name)
+ else:
+ return object.__getattribute__ (self, name)
+
+ def __getitem__(self, key):
+ return object.__getattribute__ (self, "__internal_object").__getitem__ (key)
+
+ def __setattr__ (self, name, value):
+ raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))
+
+ def __repr__ (self):
+ return "const %s" % object.__getattribute__ (self, "__internal_object").__repr__ ()
+
+ def __str__(self):
+ return object.__getattribute__ (self, "__internal_object").__str__ ()
+
+ def __add__(self, other):
+ raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))
+
+ def __delattr__ (self, name, value):
+ raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))
+
+ def __setitem__(self, key, value):
+ raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))
+
+ def __delitem__(self, key):
+ raise TypeError ("Const %s cannot be modified" % type (object.__getattribute__ (self, "__internal_object")))