Merge with 'remap/master'
diff --git a/js/Name.js b/js/Name.js
index 1c404fd..fd97d37 100644
--- a/js/Name.js
+++ b/js/Name.js
@@ -3,24 +3,29 @@
* See COPYING for copyright and distribution information.
* This class represents a Name as an array of components where each is a byte array.
*/
-
+
/*
* Create a new Name from _components.
- * If _components is a string, parse it as a URI. Otherwise it is an array of components
- * where each is a string, byte array, ArrayBuffer or Uint8Array.
+ * If _components is a string, parse it as a URI.
+ * If _components is a Name, add a deep copy of its components.
+ * Otherwise it is an array of components where each is a string, byte array, ArrayBuffer, Uint8Array
+ * or Name.
* Convert and store as an array of Uint8Array.
* If a component is a string, encode as utf8.
*/
var Name = function Name(_components){
- if( typeof _components == 'string') {
+ if( typeof _components == 'string') {
if(LOG>3)console.log('Content Name String '+_components);
this.components = Name.createNameArray(_components);
}
- else if(typeof _components === 'object'){
- if(LOG>4)console.log('Content Name Array '+_components);
+ else if(typeof _components === 'object'){
this.components = [];
- for (var i = 0; i < _components.length; ++i)
- this.add(_components[i]);
+ if (_components instanceof Name)
+ this.add(_components);
+ else {
+ for (var i = 0; i < _components.length; ++i)
+ this.add(_components[i]);
+ }
}
else if(_components==null)
this.components =[];
@@ -48,7 +53,7 @@
// Omit the leading protocol such as ndn:
name = name.substr(iColon + 1, name.length - iColon - 1).trim();
}
-
+
if (name[0] == '/') {
if (name.length >= 2 && name[1] == '/') {
// Strip the authority following "//".
@@ -64,15 +69,15 @@
}
var array = name.split('/');
-
+
// Unescape the components.
for (var i = 0; i < array.length; ++i) {
var component = Name.fromEscapedString(array[i]);
-
+
if (component == null) {
// Ignore the illegal componenent. This also gets rid of a trailing '/'.
array.splice(i, 1);
- --i;
+ --i;
continue;
}
else
@@ -86,19 +91,19 @@
Name.prototype.from_ccnb = function(/*XMLDecoder*/ decoder) {
decoder.readStartElement(this.getElementLabel());
-
+
this.components = new Array(); //new ArrayList<byte []>();
while (decoder.peekStartElement(CCNProtocolDTags.Component)) {
this.add(decoder.readBinaryElement(CCNProtocolDTags.Component));
}
-
+
decoder.readEndElement();
};
Name.prototype.to_ccnb = function(/*XMLEncoder*/ encoder) {
-
- if( this.components ==null )
+
+ if( this.components ==null )
throw new Error("CANNOT ENCODE EMPTY CONTENT NAME");
encoder.writeStartElement(this.getElementLabel());
@@ -114,48 +119,44 @@
};
/*
- * component is a string, byte array, ArrayBuffer or Uint8Array.
+ * component is a string, byte array, ArrayBuffer, Uint8Array or Name.
* Convert to Uint8Array and add to this Name.
* If a component is a string, encode as utf8.
- * Return the converted value.
+ * Return this Name object to allow chaining calls to add.
*/
Name.prototype.add = function(component){
var result;
- if(typeof component == 'string') {
+ if(typeof component == 'string')
result = DataUtils.stringToUtf8Array(component);
- this.components.push (result);
- }
- else if(typeof component == 'object' && component instanceof Uint8Array) {
+ else if(typeof component == 'object' && component instanceof Uint8Array)
result = new Uint8Array(component);
- this.components.push (result);
- }
- else if(typeof component == 'object' && component instanceof ArrayBuffer) {
+ else if(typeof component == 'object' && component instanceof ArrayBuffer) {
// Make a copy. Don't use ArrayBuffer.slice since it isn't always supported.
result = new Uint8Array(new ArrayBuffer(component.byteLength));
result.set(new Uint8Array(component));
- this.components.push(result);
}
- else if(typeof component == 'object' && component instanceof Name) {
- components = component;
- if (this == component) {
- components = new Name (component.components); // special case, when we need to create a copy
- }
- for(var i = 0; i < components.components.length; ++i) {
- result = new Uint8Array (components.components[i]);
- this.components.push (result);
- }
+ else if (typeof component == 'object' && component instanceof Name) {
+ var components;
+ if (component == this)
+ // special case, when we need to create a copy
+ components = this.components.slice(0, this.components.length);
+ else
+ components = component.components;
+
+ for (var i = 0; i < components.length; ++i)
+ this.components.push(new Uint8Array(components[i]));
+ return this;
}
- else if(typeof component == 'object') {
+ else if(typeof component == 'object')
// Assume component is a byte array. We can't check instanceof Array because
// this doesn't work in JavaScript if the array comes from a different module.
result = new Uint8Array(component);
- this.components.push(result);
- }
- else
- throw new Error("Cannot add Name element at index " + this.components.length +
- ": Invalid type");
-
- return this;
+ else
+ throw new Error("Cannot add Name element at index " + this.components.length +
+ ": Invalid type");
+
+ this.components.push(result);
+ return this;
};
/**
@@ -192,16 +193,36 @@
}
// Return the escaped name string according to "CCNx URI Scheme".
-Name.prototype.to_uri = function() {
+Name.prototype.to_uri = function() {
if (this.components.length == 0)
return "/";
-
+
var result = "";
-
+
for(var i = 0; i < this.components.length; ++i)
result += "/"+ Name.toEscapedString(this.components[i]);
+
+ return result;
+};
- return result;
+/**
+* @brief Add component that represents a segment number
+*
+* @param number Segment number (integer is expected)
+*
+* This component has a special format handling:
+* - if number is zero, then %00 is added
+* - if number is between 1 and 255, %00%01 .. %00%FF is added
+* - ...
+*/
+Name.prototype.addSegment = function(number) {
+ var segmentNumberBigEndian = DataUtils.nonNegativeIntToBigEndian(number);
+ // Put a 0 byte in front.
+ var segmentNumberComponent = new Uint8Array(segmentNumberBigEndian.length + 1);
+ segmentNumberComponent.set(segmentNumberBigEndian, 1);
+
+ this.components.push(segmentNumberComponent);
+ return this;
};
/*
@@ -230,14 +251,14 @@
var component = this.components[i];
if (component.length <= 0)
continue;
-
- if (component[0] == 0 || component[0] == 0xC0 || component[0] == 0xC1 ||
+
+ if (component[0] == 0 || component[0] == 0xC0 || component[0] == 0xC1 ||
(component[0] >= 0xF5 && component[0] <= 0xFF))
continue;
-
+
return i;
}
-
+
return -1;
}
@@ -247,18 +268,18 @@
Name.prototype.equalsName = function(name) {
if (this.components.length != name.components.length)
return false;
-
+
// Start from the last component because they are more likely to differ.
for (var i = this.components.length - 1; i >= 0; --i) {
if (!DataUtils.arraysEqual(this.components[i], name.components[i]))
return false;
}
-
+
return true;
}
/*
- * Find the last component in name that has a ContentDigest and return the digest value as Uint8Array,
+ * Find the last component in name that has a ContentDigest and return the digest value as Uint8Array,
* or null if not found. See Name.getComponentContentDigestValue.
*/
Name.prototype.getContentDigestValue = function() {
@@ -267,7 +288,7 @@
if (digestValue != null)
return digestValue;
}
-
+
return null;
}
@@ -277,10 +298,10 @@
* A ContentDigest component is Name.ContentDigestPrefix + 32 bytes + Name.ContentDigestSuffix.
*/
Name.getComponentContentDigestValue = function(component) {
- var digestComponentLength = Name.ContentDigestPrefix.length + 32 + Name.ContentDigestSuffix.length;
+ var digestComponentLength = Name.ContentDigestPrefix.length + 32 + Name.ContentDigestSuffix.length;
// Check for the correct length and equal ContentDigestPrefix and ContentDigestSuffix.
if (component.length == digestComponentLength &&
- DataUtils.arraysEqual(component.subarray(0, Name.ContentDigestPrefix.length),
+ DataUtils.arraysEqual(component.subarray(0, Name.ContentDigestPrefix.length),
Name.ContentDigestPrefix) &&
DataUtils.arraysEqual(component.subarray
(component.length - Name.ContentDigestSuffix.length, component.length),
@@ -290,7 +311,7 @@
return null;
}
-// Meta GUID "%C1.M.G%C1" + ContentDigest with a 32 byte BLOB.
+// Meta GUID "%C1.M.G%C1" + ContentDigest with a 32 byte BLOB.
Name.ContentDigestPrefix = new Uint8Array([0xc1, 0x2e, 0x4d, 0x2e, 0x47, 0xc1, 0x01, 0xaa, 0x02, 0x85]);
Name.ContentDigestSuffix = new Uint8Array([0x00]);
@@ -318,7 +339,7 @@
var value = component[i];
// Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
if (value >= 0x30 && value <= 0x39 || value >= 0x41 && value <= 0x5a ||
- value >= 0x61 && value <= 0x7a || value == 0x2b || value == 0x2d ||
+ value >= 0x61 && value <= 0x7a || value == 0x2b || value == 0x2d ||
value == 0x2e || value == 0x5f)
result += String.fromCharCode(value);
else
@@ -334,9 +355,9 @@
*/
Name.fromEscapedString = function(escapedString) {
var component = unescape(escapedString.trim());
-
+
if (component.match(/[^.]/) == null) {
- // Special case for component of only periods.
+ // Special case for component of only periods.
if (component.length <= 2)
// Zero, one or two periods is illegal. Ignore this componenent to be
// consistent with the C implementation.
diff --git a/js/ndnProtocol.xpi b/js/ndnProtocol.xpi
index 720ed20..ee9d716 100644
--- a/js/ndnProtocol.xpi
+++ b/js/ndnProtocol.xpi
Binary files differ
diff --git a/js/ndnProtocol/components/ndnProtocolService.js b/js/ndnProtocol/components/ndnProtocolService.js
index 012e8e4..975a6b5 100644
--- a/js/ndnProtocol/components/ndnProtocolService.js
+++ b/js/ndnProtocol/components/ndnProtocolService.js
@@ -85,12 +85,9 @@
var requestContent = function(contentListener) {
var name = new Name(uriParts.name);
- // TODO: Strip off an ending implicit digest before checking the last component?
- var uriEndsWithSegmentNumber = endsWithSegmentNumber(name);
-
// Use the same NDN object each time.
thisNdnProtocol.ndn.expressInterest(name, new ExponentialReExpressClosure
- (new ContentClosure(thisNdnProtocol.ndn, contentListener, uriEndsWithSegmentNumber,
+ (new ContentClosure(thisNdnProtocol.ndn, contentListener, name,
aURI, searchWithoutNdn + uriParts.hash, segmentTemplate)),
template);
};
@@ -115,8 +112,8 @@
/*
* Create a closure for calling expressInterest.
* contentListener is from the call to requestContent.
- * uriEndsWithSegmentNumber is true if the URI passed to newChannel has a segment number
- * (used to determine whether to request only that segment number and for updating the URL bar).
+ * uriName is the name in the URI passed to newChannel (used in part to determine whether to request
+ * only that segment number and for updating the URL bar).
* aURI is the URI passed to newChannel.
* uriSearchAndHash is the search and hash part of the URI passed to newChannel, including the '?'
* and/or '#' but without the interest selector fields.
@@ -124,14 +121,13 @@
* The uses ExponentialReExpressClosure in expressInterest to re-express if fetching a segment times out.
*/
var ContentClosure = function ContentClosure
- (ndn, contentListener, uriEndsWithSegmentNumber, aURI, uriSearchAndHash,
- segmentTemplate) {
+ (ndn, contentListener, uriName, aURI, uriSearchAndHash, segmentTemplate) {
// Inherit from Closure.
Closure.call(this);
this.ndn = ndn;
this.contentListener = contentListener;
- this.uriEndsWithSegmentNumber = uriEndsWithSegmentNumber;
+ this.uriName = uriName;
this.aURI = aURI;
this.uriSearchAndHash = uriSearchAndHash;
this.segmentTemplate = segmentTemplate;
@@ -141,6 +137,7 @@
this.didRequestFinalSegment = false;
this.finalSegmentNumber = null;
this.didOnStart = false;
+ this.uriEndsWithSegmentNumber = endsWithSegmentNumber(uriName);
};
ContentClosure.prototype.upcall = function(kind, upcallInfo) {
@@ -187,7 +184,22 @@
}
if ((segmentNumber == null || segmentNumber == 0) && !this.didOnStart) {
- // This is the first or only segment, so start.
+ // This is the first or only segment.
+ /* TODO: Finish implementing check for META.
+ var iMetaComponent = getIndexOfMetaComponent(contentObject.name);
+ if (!this.uriEndsWithSegmentNumber && iMetaComponent >= 0 &&
+ getIndexOfMetaComponent(this.uriName) < 0) {
+ // The matched content name has a META component that wasn't requiested in the original
+ // URI. Try to exclude the META component to get the "real" content.
+ var nameWithoutMeta = new Name(contentObject.name.components.slice(0, iMetaComponent));
+ var excludeMetaTemplate = this.segmentTemplate.clone();
+ excludeMetaTemplate.exclude = new Exclude([MetaComponentPrefix, Exclude.ANY]);
+
+ this.ndn.expressInterest
+ (nameWithoutMeta, new ExponentialReExpressClosure(this), excludeMetaTemplate);
+ }
+ */
+
this.didOnStart = true;
// Get the URI from the ContentObject including the version.
@@ -255,11 +267,11 @@
var components = contentObject.name.components.slice
(0, contentObject.name.components.length - 1);
- // Temporarily set the childSelector in the segmentTemplate.
- this.segmentTemplate.childSelector = 1;
+ // Clone the template to set the childSelector.
+ var childSelectorTemplate = this.segmentTemplate.clone();
+ childSelectorTemplate.childSelector = 1;
this.ndn.expressInterest
- (new Name(components), new ExponentialReExpressClosure(this), this.segmentTemplate);
- this.segmentTemplate.childSelector = null;
+ (new Name(components), new ExponentialReExpressClosure(this), childSelectorTemplate);
}
// Request new segments.
@@ -268,17 +280,10 @@
if (this.finalSegmentNumber != null && toRequest[i] > this.finalSegmentNumber)
continue;
- // Make a name for the segment and get it.
- var segmentNumberBigEndian = DataUtils.nonNegativeIntToBigEndian(toRequest[i]);
- // Put a 0 byte in front.
- var segmentNumberComponent = new Uint8Array(segmentNumberBigEndian.length + 1);
- segmentNumberComponent.set(segmentNumberBigEndian, 1);
-
- var components = contentObject.name.components.slice
- (0, contentObject.name.components.length - 1);
- components.push(segmentNumberComponent);
this.ndn.expressInterest
- (new Name(components), new ExponentialReExpressClosure(this), this.segmentTemplate);
+ (new Name(contentObject.name.components.slice
+ (0, contentObject.name.components.length - 1)).addSegment(toRequest[i]),
+ new ExponentialReExpressClosure(this), this.segmentTemplate);
}
return Closure.RESULT_OK;
@@ -490,10 +495,27 @@
for (var i = 0; i < splitValue.length; ++i) {
var element = splitValue[i].trim();
if (element == "*")
- excludeValues.push("*")
+ excludeValues.push(Exclude.ANY)
else
excludeValues.push(Name.fromEscapedString(element));
}
return new Exclude(excludeValues);
}
+
+/*
+ * Return the index of the first compoment that starts with %C1.META, or -1 if not found.
+ */
+function getIndexOfMetaComponent(name) {
+ for (var i = 0; i < name.components.length; ++i) {
+ var component = name.components[i];
+ if (component.length >= MetaComponentPrefix.length &&
+ DataUtils.arraysEqual(component.subarray(0, MetaComponentPrefix.length),
+ MetaComponentPrefix))
+ return i;
+ }
+
+ return -1;
+}
+
+var MetaComponentPrefix = new Uint8Array([0xc1, 0x2e, 0x4d, 0x45, 0x54, 0x41]);
diff --git a/js/ndnProtocol/modules/ndn-js.jsm b/js/ndnProtocol/modules/ndn-js.jsm
index 0a15cf4..0719199 100644
--- a/js/ndnProtocol/modules/ndn-js.jsm
+++ b/js/ndnProtocol/modules/ndn-js.jsm
@@ -36,7 +36,7 @@
}
var Closure=function(){this.ndn_data=null;this.ndn_data_dirty=!1};Closure.RESULT_ERR=-1;Closure.RESULT_OK=0;Closure.RESULT_REEXPRESS=1;Closure.RESULT_INTEREST_CONSUMED=2;Closure.RESULT_VERIFY=3;Closure.RESULT_FETCHKEY=4;Closure.UPCALL_FINAL=0;Closure.UPCALL_INTEREST=1;Closure.UPCALL_CONSUMED_INTEREST=2;Closure.UPCALL_CONTENT=3;Closure.UPCALL_INTEREST_TIMED_OUT=4;Closure.UPCALL_CONTENT_UNVERIFIED=5;Closure.UPCALL_CONTENT_BAD=6;Closure.prototype.upcall=function(){return Closure.RESULT_OK};
var UpcallInfo=function(a,b,c,d){this.ndn=a;this.interest=b;this.matchedComps=c;this.contentObject=d};UpcallInfo.prototype.toString=function(){var a="ndn = "+this.ndn,a=a+("\nInterest = "+this.interest),a=a+("\nmatchedComps = "+this.matchedComps);return a+="\nContentObject: "+this.contentObject};
-var WebSocketTransport=function(){this.elementReader=this.connectedPort=this.connectedHost=this.ws=null;this.defaultGetHostAndPort=NDN.makeShuffledGetHostAndPort(["A.ws.ndn.ucla.edu","B.ws.ndn.ucla.edu","C.ws.ndn.ucla.edu","D.ws.ndn.ucla.edu","E.ws.ndn.ucla.edu"],9696)};
+var WebSocketTransport=function(){if(!WebSocket)throw Error("WebSocket support is not available on this platform.");this.elementReader=this.connectedPort=this.connectedHost=this.ws=null;this.defaultGetHostAndPort=NDN.makeShuffledGetHostAndPort(["A.ws.ndn.ucla.edu","B.ws.ndn.ucla.edu","C.ws.ndn.ucla.edu","D.ws.ndn.ucla.edu","E.ws.ndn.ucla.edu"],9696)};
WebSocketTransport.prototype.connect=function(a,b){null!=this.ws&&delete this.ws;this.ws=new WebSocket("ws://"+a.host+":"+a.port);0<LOG&&console.log("ws connection created.");this.connectedHost=a.host;this.connectedPort=a.port;this.ws.binaryType="arraybuffer";this.elementReader=new BinaryXmlElementReader(a);var c=this;this.ws.onmessage=function(a){a=a.data;if(null==a||void 0==a||""==a)console.log("INVALID ANSWER");else if(a instanceof ArrayBuffer){a=new Uint8Array(a);3<LOG&&console.log("BINARY RESPONSE IS "+
DataUtils.toHex(a));try{c.elementReader.onReceivedData(a)}catch(b){console.log("NDN.ws.onmessage exception: "+b)}}};this.ws.onopen=function(a){3<LOG&&console.log(a);3<LOG&&console.log("ws.onopen: WebSocket connection opened.");3<LOG&&console.log("ws.onopen: ReadyState: "+this.readyState);b()};this.ws.onerror=function(a){console.log("ws.onerror: ReadyState: "+this.readyState);console.log(a);console.log("ws.onerror: WebSocket error: "+a.data)};this.ws.onclose=function(){console.log("ws.onclose: WebSocket connection closed.");
c.ws=null;a.readyStatus=NDN.CLOSED;a.onclose()}};WebSocketTransport.prototype.send=function(a){if(null!=this.ws){var b=new Uint8Array(a.length);b.set(a);this.ws.send(b.buffer);3<LOG&&console.log("ws.send() returned.")}else console.log("WebSocket connection is not established.")};
@@ -54,9 +54,9 @@
Name.prototype.from_ccnb=function(a){a.readStartElement(this.getElementLabel());for(this.components=[];a.peekStartElement(CCNProtocolDTags.Component);)this.add(a.readBinaryElement(CCNProtocolDTags.Component));a.readEndElement()};Name.prototype.to_ccnb=function(a){if(null==this.components)throw Error("CANNOT ENCODE EMPTY CONTENT NAME");a.writeStartElement(this.getElementLabel());for(var b=this.components.length,c=0;c<b;c++)a.writeElement(CCNProtocolDTags.Component,this.components[c]);a.writeEndElement()};
Name.prototype.getElementLabel=function(){return CCNProtocolDTags.Name};
Name.prototype.add=function(a){var b;if("string"==typeof a)b=DataUtils.stringToUtf8Array(a);else if("object"==typeof a&&a instanceof Uint8Array)b=new Uint8Array(a);else if("object"==typeof a&&a instanceof ArrayBuffer)b=new Uint8Array(new ArrayBuffer(a.byteLength)),b.set(new Uint8Array(a));else if("object"==typeof a)b=new Uint8Array(a);else throw Error("Cannot add Name element at index "+this.components.length+": Invalid type");return this.components.push(b)};
-Name.prototype.to_uri=function(){if(0==this.components.length)return"/";for(var a="",b=0;b<this.components.length;++b)a+="/"+Name.toEscapedString(this.components[b]);return a};Name.prototype.getPrefix=function(a){return new Name(this.components.slice(0,a))};Name.prototype.getComponent=function(a){var b=new ArrayBuffer(this.components[a].length);(new Uint8Array(b)).set(this.components[a]);return b};
-Name.prototype.indexOfFileName=function(){for(var a=this.components.length-1;0<=a;--a){var b=this.components[a];if(!(0>=b.length)&&!(0==b[0]||192==b[0]||193==b[0]||245<=b[0]&&255>=b[0]))return a}return-1};Name.prototype.equalsName=function(a){if(this.components.length!=a.components.length)return!1;for(var b=this.components.length-1;0<=b;--b)if(!DataUtils.arraysEqual(this.components[b],a.components[b]))return!1;return!0};
-Name.prototype.getContentDigestValue=function(){for(var a=this.components.length-1;0<=a;--a){var b=Name.getComponentContentDigestValue(this.components[a]);if(null!=b)return b}return null};
+Name.prototype.to_uri=function(){if(0==this.components.length)return"/";for(var a="",b=0;b<this.components.length;++b)a+="/"+Name.toEscapedString(this.components[b]);return a};Name.prototype.addSegment=function(a){var a=DataUtils.nonNegativeIntToBigEndian(a),b=new Uint8Array(a.length+1);b.set(a,1);this.components.push(b);return this};Name.prototype.getPrefix=function(a){return new Name(this.components.slice(0,a))};
+Name.prototype.getComponent=function(a){var b=new ArrayBuffer(this.components[a].length);(new Uint8Array(b)).set(this.components[a]);return b};Name.prototype.indexOfFileName=function(){for(var a=this.components.length-1;0<=a;--a){var b=this.components[a];if(!(0>=b.length)&&!(0==b[0]||192==b[0]||193==b[0]||245<=b[0]&&255>=b[0]))return a}return-1};
+Name.prototype.equalsName=function(a){if(this.components.length!=a.components.length)return!1;for(var b=this.components.length-1;0<=b;--b)if(!DataUtils.arraysEqual(this.components[b],a.components[b]))return!1;return!0};Name.prototype.getContentDigestValue=function(){for(var a=this.components.length-1;0<=a;--a){var b=Name.getComponentContentDigestValue(this.components[a]);if(null!=b)return b}return null};
Name.getComponentContentDigestValue=function(a){return a.length==Name.ContentDigestPrefix.length+32+Name.ContentDigestSuffix.length&&DataUtils.arraysEqual(a.subarray(0,Name.ContentDigestPrefix.length),Name.ContentDigestPrefix)&&DataUtils.arraysEqual(a.subarray(a.length-Name.ContentDigestSuffix.length,a.length),Name.ContentDigestSuffix)?a.subarray(Name.ContentDigestPrefix.length,Name.ContentDigestPrefix.length+32):null};Name.ContentDigestPrefix=new Uint8Array([193,46,77,46,71,193,1,170,2,133]);
Name.ContentDigestSuffix=new Uint8Array([0]);Name.toEscapedString=function(a){for(var b="",c=!1,d=0;d<a.length;++d)if(46!=a[d]){c=!0;break}if(c)for(d=0;d<a.length;++d)c=a[d],b=48<=c&&57>=c||65<=c&&90>=c||97<=c&&122>=c||43==c||45==c||46==c||95==c?b+String.fromCharCode(c):b+("%"+(16>c?"0":"")+c.toString(16).toUpperCase());else{b="...";for(d=0;d<a.length;++d)b+="."}return b};
Name.fromEscapedString=function(a){a=unescape(a.trim());return null==a.match(/[^.]/)?2>=a.length?null:DataUtils.toNumbersFromString(a.substr(3,a.length-3)):DataUtils.toNumbersFromString(a)};Name.prototype.match=function(a){var b=this.components,a=a.components;if(b.length>a.length)return!1;for(var c=0;c<b.length;++c)if(!DataUtils.arraysEqual(b[c],a[c]))return!1;return!0};
@@ -290,11 +290,11 @@
BigInteger.prototype.millerRabin=bnpMillerRabin;BigInteger.prototype.clone=bnClone;BigInteger.prototype.intValue=bnIntValue;BigInteger.prototype.byteValue=bnByteValue;BigInteger.prototype.shortValue=bnShortValue;BigInteger.prototype.signum=bnSigNum;BigInteger.prototype.toByteArray=bnToByteArray;BigInteger.prototype.equals=bnEquals;BigInteger.prototype.min=bnMin;BigInteger.prototype.max=bnMax;BigInteger.prototype.and=bnAnd;BigInteger.prototype.or=bnOr;BigInteger.prototype.xor=bnXor;
BigInteger.prototype.andNot=bnAndNot;BigInteger.prototype.not=bnNot;BigInteger.prototype.shiftLeft=bnShiftLeft;BigInteger.prototype.shiftRight=bnShiftRight;BigInteger.prototype.getLowestSetBit=bnGetLowestSetBit;BigInteger.prototype.bitCount=bnBitCount;BigInteger.prototype.testBit=bnTestBit;BigInteger.prototype.setBit=bnSetBit;BigInteger.prototype.clearBit=bnClearBit;BigInteger.prototype.flipBit=bnFlipBit;BigInteger.prototype.add=bnAdd;BigInteger.prototype.subtract=bnSubtract;
BigInteger.prototype.multiply=bnMultiply;BigInteger.prototype.divide=bnDivide;BigInteger.prototype.remainder=bnRemainder;BigInteger.prototype.divideAndRemainder=bnDivideAndRemainder;BigInteger.prototype.modPow=bnModPow;BigInteger.prototype.modInverse=bnModInverse;BigInteger.prototype.pow=bnPow;BigInteger.prototype.gcd=bnGCD;BigInteger.prototype.isProbablePrime=bnIsProbablePrime;
-var LOG=0,NDN=function NDN(b){b=b||{};this.transport=(b.getTransport||function(){return new WebSocketTransport})();this.getHostAndPort=b.getHostAndPort||this.transport.defaultGetHostAndPort;this.host=void 0!==b.host?b.host:null;this.port=b.port||9696;this.readyStatus=NDN.UNOPEN;this.verify=void 0!==b.verify?b.verify:!0;this.onopen=b.onopen||function(){3<LOG&&console.log("NDN connection established.")};this.onclose=b.onclose||function(){3<LOG&&console.log("NDN connection closed.")};this.ccndid=null};
-NDN.UNOPEN=0;NDN.OPENED=1;NDN.CLOSED=2;NDN.ccndIdFetcher=new Name("/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY");NDN.prototype.createRoute=function(a,b){this.host=a;this.port=b};NDN.KeyStore=[];var KeyStoreEntry=function(a,b,c){this.keyName=a;this.rsaKey=b;this.timeStamp=c};NDN.addKeyEntry=function(a){null==NDN.getKeyByName(a.keyName)&&NDN.KeyStore.push(a)};
-NDN.getKeyByName=function(a){for(var b=null,c=0;c<NDN.KeyStore.length;c++)if(NDN.KeyStore[c].keyName.contentName.match(a.contentName)&&(null==b||NDN.KeyStore[c].keyName.contentName.components.length>b.keyName.contentName.components.length))b=NDN.KeyStore[c];return b};NDN.PITTable=[];var PITEntry=function(a,b){this.interest=a;this.closure=b;this.timerID=-1};
-NDN.getEntryForExpressedInterest=function(a){for(var b=null,c=0;c<NDN.PITTable.length;c++)if(NDN.PITTable[c].interest.matches_name(a)&&(null==b||NDN.PITTable[c].interest.name.components.length>b.interest.name.components.length))b=NDN.PITTable[c];return b};NDN.CSTable=[];var CSEntry=function(a,b){this.name=a;this.closure=b};function getEntryForRegisteredPrefix(a){for(var b=0;b<NDN.CSTable.length;b++)if(null!=NDN.CSTable[b].name.match(a))return NDN.CSTable[b];return null}
-NDN.makeShuffledGetHostAndPort=function(a,b){a=a.slice(0,a.length);DataUtils.shuffle(a);return function(){return 0==a.length?null:{host:a.splice(0,1)[0],port:b}}};
+var LOG=0,NDN=function NDN(b){if(!NDN.supported)throw Error("The necessary JavaScript support is not available on this platform.");b=b||{};this.transport=(b.getTransport||function(){return new WebSocketTransport})();this.getHostAndPort=b.getHostAndPort||this.transport.defaultGetHostAndPort;this.host=void 0!==b.host?b.host:null;this.port=b.port||9696;this.readyStatus=NDN.UNOPEN;this.verify=void 0!==b.verify?b.verify:!0;this.onopen=b.onopen||function(){3<LOG&&console.log("NDN connection established.")};
+this.onclose=b.onclose||function(){3<LOG&&console.log("NDN connection closed.")};this.ccndid=null};NDN.UNOPEN=0;NDN.OPENED=1;NDN.CLOSED=2;NDN.getSupported=function(){try{(new Uint8Array(1)).subarray(0,1)}catch(a){return console.log("NDN not available: Uint8Array not supported. "+a),!1}return!0};NDN.supported=NDN.getSupported();NDN.ccndIdFetcher=new Name("/%C1.M.S.localhost/%C1.M.SRV/ccnd/KEY");NDN.prototype.createRoute=function(a,b){this.host=a;this.port=b};NDN.KeyStore=[];
+var KeyStoreEntry=function(a,b,c){this.keyName=a;this.rsaKey=b;this.timeStamp=c};NDN.addKeyEntry=function(a){null==NDN.getKeyByName(a.keyName)&&NDN.KeyStore.push(a)};NDN.getKeyByName=function(a){for(var b=null,c=0;c<NDN.KeyStore.length;c++)if(NDN.KeyStore[c].keyName.contentName.match(a.contentName)&&(null==b||NDN.KeyStore[c].keyName.contentName.components.length>b.keyName.contentName.components.length))b=NDN.KeyStore[c];return b};NDN.PITTable=[];
+var PITEntry=function(a,b){this.interest=a;this.closure=b;this.timerID=-1};NDN.getEntryForExpressedInterest=function(a){for(var b=null,c=0;c<NDN.PITTable.length;c++)if(NDN.PITTable[c].interest.matches_name(a)&&(null==b||NDN.PITTable[c].interest.name.components.length>b.interest.name.components.length))b=NDN.PITTable[c];return b};NDN.CSTable=[];var CSEntry=function(a,b){this.name=a;this.closure=b};
+function getEntryForRegisteredPrefix(a){for(var b=0;b<NDN.CSTable.length;b++)if(null!=NDN.CSTable[b].name.match(a))return NDN.CSTable[b];return null}NDN.makeShuffledGetHostAndPort=function(a,b){a=a.slice(0,a.length);DataUtils.shuffle(a);return function(){return 0==a.length?null:{host:a.splice(0,1)[0],port:b}}};
NDN.prototype.expressInterest=function(a,b,c){var d=new Interest(a);null!=c?(d.minSuffixComponents=c.minSuffixComponents,d.maxSuffixComponents=c.maxSuffixComponents,d.publisherPublicKeyDigest=c.publisherPublicKeyDigest,d.exclude=c.exclude,d.childSelector=c.childSelector,d.answerOriginKind=c.answerOriginKind,d.scope=c.scope,d.interestLifetime=c.interestLifetime):d.interestLifetime=4E3;if(null==this.host||null==this.port)if(null==this.getHostAndPort)console.log("ERROR: host OR port NOT SET");else{var e=
this;this.connectAndExecute(function(){e.reconnectAndExpressInterest(d,b)})}else this.reconnectAndExpressInterest(d,b)};NDN.prototype.reconnectAndExpressInterest=function(a,b){if(this.transport.connectedHost!=this.host||this.transport.connectedPort!=this.port){var c=this;this.transport.connect(c,function(){c.expressInterestHelper(a,b)})}else this.expressInterestHelper(a,b)};
NDN.prototype.expressInterestHelper=function(a,b){var c=encodeToBinaryInterest(a),d=this;if(null!=b){var e=new PITEntry(a,b);NDN.PITTable.push(e);b.pitEntry=e;var f=a.interestLifetime||4E3,g=function(){3<LOG&&console.log("Interest time out: "+a.name.to_uri());var h=NDN.PITTable.indexOf(e);0<=h&&NDN.PITTable.splice(h,1);b.upcall(Closure.UPCALL_INTEREST_TIMED_OUT,new UpcallInfo(d,a,0,null))==Closure.RESULT_REEXPRESS&&(3<LOG&&console.log("Re-express interest: "+a.name.to_uri()),e.timerID=setTimeout(g,
diff --git a/js/testing/test-name.html b/js/testing/test-name.html
index aca50d9..318511d 100644
--- a/js/testing/test-name.html
+++ b/js/testing/test-name.html
@@ -32,73 +32,81 @@
var name1 = new Name([entree, comp1, ab2]);
var name1Uri = name1.to_uri();
var name1UriExpected = "/entr%C3%A9e/..../%00%01%02%03";
- result.innerHTML += "Name from '" + entree + "', Uint8Array of '.' and ArrayBuffer of 0,1,2,3:<br>";
+ result.innerHTML += "Name from '" + entree + "', Uint8Array of '.' and ArrayBuffer of 0,1,2,3:<br/>";
if (name1Uri == name1UriExpected)
- result.innerHTML += "SUCCESS: " + name1Uri + ".<br>";
+ result.innerHTML += "SUCCESS: " + name1Uri + ".<br/>";
else
- result.innerHTML += "ERROR: got " + name1Uri + ", expected " + name1UriExpected + " .<br>";
+ result.innerHTML += "ERROR: got " + name1Uri + ", expected " + name1UriExpected + " .<br/>";
- result.innerHTML += "Compare with same Name from '" + entree + "', '.' and ArrayBuffer:<br>";
+ result.innerHTML += "Compare with same Name from '" + entree + "', '.' and ArrayBuffer:<br/>";
// Equivalent with name1
var name2 = new Name([entree, ".", comp2]);
if (name2.components.length != name1.components.length)
result.innerHTML += "ERROR: Got name with " + name2.components.length +
- " components, expected " + name1.components.length + ".<br>";
+ " components, expected " + name1.components.length + ".<br/>";
else {
var allEqual = true;
for (var i = 0; i < name1.components.length; ++i) {
if (!DataUtils.arraysEqual(name1.components[i], name2.components[i])) {
allEqual = false;
- result.innerHTML += "ERROR: Names differ at component at index " + i + ".<br>";
+ result.innerHTML += "ERROR: Names differ at component at index " + i + ".<br/>";
}
}
if (allEqual)
- result.innerHTML += "SUCCESS: Names are equal.<br>";
+ result.innerHTML += "SUCCESS: Names are equal.<br/>";
}
- result.innerHTML += "Compare with same Name from URI:<br>";
+ result.innerHTML += "Compare with same Name from URI:<br/>";
// Equivalent with name1; when Name constructor is passed a string, it is treated as a URI
var name3 = new Name("/entr%C3%A9e/..../%00%01%02%03");
if (name3.components.length != name1.components.length)
result.innerHTML += "ERROR: Got name with " + name3.components.length +
- " components, expected " + name1.components.length + ".<br>";
+ " components, expected " + name1.components.length + ".<br/>";
else {
var allEqual = true;
for (var i = 0; i < name1.components.length; ++i) {
if (!DataUtils.arraysEqual(name1.components[i], name3.components[i])) {
allEqual = false;
- result.innerHTML += "ERROR: Names differ at component at index " + i + ".<br>";
+ result.innerHTML += "ERROR: Names differ at component at index " + i + ".<br/>";
}
}
if (allEqual)
- result.innerHTML += "SUCCESS: Names are equal.<br>";
+ result.innerHTML += "SUCCESS: Names are equal.<br/>";
}
- result.innerHTML += "Compare with Name prefix of first 2 components:<br>";
+ result.innerHTML += "Compare with Name prefix of first 2 components:<br/>";
// Returns new Name([entree, "."])
var name4 = name2.getPrefix(2);
if (name4.components.length != 2)
result.innerHTML += "ERROR: Got name with " + name4.components.length +
- " components, expected 2.<br>";
+ " components, expected 2.<br/>";
else {
var allEqual = true;
for (var i = 0; i < name4.components.length; ++i) {
if (!DataUtils.arraysEqual(name1.components[i], name4.components[i])) {
allEqual = false;
- result.innerHTML += "ERROR: Names differ at component at index " + i + ".<br>";
+ result.innerHTML += "ERROR: Names differ at component at index " + i + ".<br/>";
}
}
if (allEqual)
- result.innerHTML += "SUCCESS: First 2 components are equal: " + name4.to_uri() + " .<br>";
+ result.innerHTML += "SUCCESS: First 2 components are equal: " + name4.to_uri() + " .<br/>";
}
- result.innerHTML += "Check with Name component at index 2:<br>";
+ result.innerHTML += "Check with Name component at index 2:<br/>";
// Returns ArrayBuffer of "%00%01%02%03"
var component2Out = new Uint8Array(name1.getComponent(2));
if (DataUtils.arraysEqual(component2Out, comp2))
- result.innerHTML += "SUCCESS: Components at index 2 are equal.<br>";
+ result.innerHTML += "SUCCESS: Components at index 2 are equal.<br/>";
else
- result.innerHTML += "ERROR: Components at index 2 are different.<br>";
+ result.innerHTML += "ERROR: Components at index 2 are different.<br/>";
+
+ var name5 = new Name("/localhost/user/folders/files/%00%0F");
+ result.innerHTML += "Check chaining calls to add() to create Name: " + name5.to_uri() + "<br/>";
+ if (name5.equalsName(new Name(new Name("/localhost")).add(new Name("/user/folders")).add
+ ("files").addSegment(15)))
+ result.innerHTML += "SUCCESS: Names are equal.<br/>";
+ else
+ result.innerHTML += "ERROR: Names are different.<br/>";
}
</script>
diff --git a/js/tools/build/ndn-js-uncomp.js b/js/tools/build/ndn-js-uncomp.js
index b947a5c..274879c 100644
--- a/js/tools/build/ndn-js-uncomp.js
+++ b/js/tools/build/ndn-js-uncomp.js
@@ -633,6 +633,26 @@
return result;
};
+/**
+* @brief Add component that represents a segment number
+*
+* @param number Segment number (integer is expected)
+*
+* This component has a special format handling:
+* - if number is zero, then %00 is added
+* - if number is between 1 and 255, %00%01 .. %00%FF is added
+* - ...
+*/
+Name.prototype.addSegment = function(number) {
+ var segmentNumberBigEndian = DataUtils.nonNegativeIntToBigEndian(number);
+ // Put a 0 byte in front.
+ var segmentNumberComponent = new Uint8Array(segmentNumberBigEndian.length + 1);
+ segmentNumberComponent.set(segmentNumberBigEndian, 1);
+
+ this.components.push(segmentNumberComponent);
+ return this;
+};
+
/*
* Return a new Name with the first nComponents components of this Name.
*/
diff --git a/js/tools/build/ndn-js.js b/js/tools/build/ndn-js.js
index fb403f1..fb07e3a 100644
--- a/js/tools/build/ndn-js.js
+++ b/js/tools/build/ndn-js.js
@@ -18,9 +18,9 @@
Name.prototype.from_ccnb=function(a){a.readStartElement(this.getElementLabel());for(this.components=[];a.peekStartElement(CCNProtocolDTags.Component);)this.add(a.readBinaryElement(CCNProtocolDTags.Component));a.readEndElement()};Name.prototype.to_ccnb=function(a){if(null==this.components)throw Error("CANNOT ENCODE EMPTY CONTENT NAME");a.writeStartElement(this.getElementLabel());for(var b=this.components.length,c=0;c<b;c++)a.writeElement(CCNProtocolDTags.Component,this.components[c]);a.writeEndElement()};
Name.prototype.getElementLabel=function(){return CCNProtocolDTags.Name};
Name.prototype.add=function(a){var b;if("string"==typeof a)b=DataUtils.stringToUtf8Array(a);else if("object"==typeof a&&a instanceof Uint8Array)b=new Uint8Array(a);else if("object"==typeof a&&a instanceof ArrayBuffer)b=new Uint8Array(new ArrayBuffer(a.byteLength)),b.set(new Uint8Array(a));else if("object"==typeof a)b=new Uint8Array(a);else throw Error("Cannot add Name element at index "+this.components.length+": Invalid type");return this.components.push(b)};
-Name.prototype.to_uri=function(){if(0==this.components.length)return"/";for(var a="",b=0;b<this.components.length;++b)a+="/"+Name.toEscapedString(this.components[b]);return a};Name.prototype.getPrefix=function(a){return new Name(this.components.slice(0,a))};Name.prototype.getComponent=function(a){var b=new ArrayBuffer(this.components[a].length);(new Uint8Array(b)).set(this.components[a]);return b};
-Name.prototype.indexOfFileName=function(){for(var a=this.components.length-1;0<=a;--a){var b=this.components[a];if(!(0>=b.length)&&!(0==b[0]||192==b[0]||193==b[0]||245<=b[0]&&255>=b[0]))return a}return-1};Name.prototype.equalsName=function(a){if(this.components.length!=a.components.length)return!1;for(var b=this.components.length-1;0<=b;--b)if(!DataUtils.arraysEqual(this.components[b],a.components[b]))return!1;return!0};
-Name.prototype.getContentDigestValue=function(){for(var a=this.components.length-1;0<=a;--a){var b=Name.getComponentContentDigestValue(this.components[a]);if(null!=b)return b}return null};
+Name.prototype.to_uri=function(){if(0==this.components.length)return"/";for(var a="",b=0;b<this.components.length;++b)a+="/"+Name.toEscapedString(this.components[b]);return a};Name.prototype.addSegment=function(a){var a=DataUtils.nonNegativeIntToBigEndian(a),b=new Uint8Array(a.length+1);b.set(a,1);this.components.push(b);return this};Name.prototype.getPrefix=function(a){return new Name(this.components.slice(0,a))};
+Name.prototype.getComponent=function(a){var b=new ArrayBuffer(this.components[a].length);(new Uint8Array(b)).set(this.components[a]);return b};Name.prototype.indexOfFileName=function(){for(var a=this.components.length-1;0<=a;--a){var b=this.components[a];if(!(0>=b.length)&&!(0==b[0]||192==b[0]||193==b[0]||245<=b[0]&&255>=b[0]))return a}return-1};
+Name.prototype.equalsName=function(a){if(this.components.length!=a.components.length)return!1;for(var b=this.components.length-1;0<=b;--b)if(!DataUtils.arraysEqual(this.components[b],a.components[b]))return!1;return!0};Name.prototype.getContentDigestValue=function(){for(var a=this.components.length-1;0<=a;--a){var b=Name.getComponentContentDigestValue(this.components[a]);if(null!=b)return b}return null};
Name.getComponentContentDigestValue=function(a){return a.length==Name.ContentDigestPrefix.length+32+Name.ContentDigestSuffix.length&&DataUtils.arraysEqual(a.subarray(0,Name.ContentDigestPrefix.length),Name.ContentDigestPrefix)&&DataUtils.arraysEqual(a.subarray(a.length-Name.ContentDigestSuffix.length,a.length),Name.ContentDigestSuffix)?a.subarray(Name.ContentDigestPrefix.length,Name.ContentDigestPrefix.length+32):null};Name.ContentDigestPrefix=new Uint8Array([193,46,77,46,71,193,1,170,2,133]);
Name.ContentDigestSuffix=new Uint8Array([0]);Name.toEscapedString=function(a){for(var b="",c=!1,d=0;d<a.length;++d)if(46!=a[d]){c=!0;break}if(c)for(d=0;d<a.length;++d)c=a[d],b=48<=c&&57>=c||65<=c&&90>=c||97<=c&&122>=c||43==c||45==c||46==c||95==c?b+String.fromCharCode(c):b+("%"+(16>c?"0":"")+c.toString(16).toUpperCase());else{b="...";for(d=0;d<a.length;++d)b+="."}return b};
Name.fromEscapedString=function(a){a=unescape(a.trim());return null==a.match(/[^.]/)?2>=a.length?null:DataUtils.toNumbersFromString(a.substr(3,a.length-3)):DataUtils.toNumbersFromString(a)};Name.prototype.match=function(a){var b=this.components,a=a.components;if(b.length>a.length)return!1;for(var c=0;c<b.length;++c)if(!DataUtils.arraysEqual(b[c],a[c]))return!1;return!0};