Source: name.js

  1. /**
  2. * This class represents a Name as an array of components where each is a byte array.
  3. * Copyright (C) 2013-2016 Regents of the University of California.
  4. * @author: Meki Cheraoui, Jeff Thompson <jefft0@remap.ucla.edu>
  5. *
  6. * This program is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU Lesser General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This program is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU Lesser General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU Lesser General Public License
  17. * along with this program. If not, see <http://www.gnu.org/licenses/>.
  18. * A copy of the GNU Lesser General Public License is in the file COPYING.
  19. */
  20. /** @ignore */
  21. var Blob = require('./util/blob.js').Blob; /** @ignore */
  22. var DataUtils = require('./encoding/data-utils.js').DataUtils; /** @ignore */
  23. var LOG = require('./log.js').Log.LOG;
  24. /**
  25. * Create a new Name from components.
  26. *
  27. * @constructor
  28. * @param {string|Name|Array<string|Array<number>|ArrayBuffer|Buffer|Name>} components if a string, parse it as a URI. If a Name, add a deep copy of its components.
  29. * Otherwise it is an array of components which are appended according to Name.append, so
  30. * convert each and store it as an array of Buffer. If a component is a string, encode as utf8.
  31. */
  32. var Name = function Name(components)
  33. {
  34. if (typeof components == 'string') {
  35. if (LOG > 3) console.log('Content Name String ' + components);
  36. this.components = Name.createNameArray(components);
  37. }
  38. else if (typeof components === 'object') {
  39. this.components = [];
  40. if (components instanceof Name)
  41. this.append(components);
  42. else {
  43. for (var i = 0; i < components.length; ++i)
  44. this.append(components[i]);
  45. }
  46. }
  47. else if (components == null)
  48. this.components = [];
  49. else
  50. if (LOG > 1) console.log("NO CONTENT NAME GIVEN");
  51. this.changeCount = 0;
  52. };
  53. exports.Name = Name;
  54. /**
  55. * Create a new Name.Component with a copy of the given value.
  56. * @param {Name.Component|String|Array<number>|ArrayBuffer|Buffer} value If the value is a string, encode it as utf8 (but don't unescape).
  57. * @constructor
  58. */
  59. Name.Component = function NameComponent(value)
  60. {
  61. if (typeof value === 'object' && value instanceof Name.Component)
  62. this.value_ = value.value_;
  63. else if (!value)
  64. this.value_ = new Blob([]);
  65. else if (typeof value === 'object' && typeof ArrayBuffer !== 'undefined' &&
  66. value instanceof ArrayBuffer)
  67. // Make a copy. Turn the value into a Uint8Array since the Buffer
  68. // constructor doesn't take an ArrayBuffer.
  69. this.value_ = new Blob(new Buffer(new Uint8Array(value)), false);
  70. else if (typeof value === 'object' && value instanceof Blob)
  71. this.value_ = value;
  72. else
  73. // Blob will make a copy if needed.
  74. this.value_ = new Blob(value);
  75. };
  76. /**
  77. * Get the component value.
  78. * @returns {Blob} The component value.
  79. */
  80. Name.Component.prototype.getValue = function()
  81. {
  82. return this.value_;
  83. };
  84. /**
  85. * @deprecated Use getValue. This method returns a Buffer which is the former
  86. * behavior of getValue, and should only be used while updating your code.
  87. */
  88. Name.Component.prototype.getValueAsBuffer = function()
  89. {
  90. // Assume the caller won't modify it.
  91. return this.value_.buf();
  92. };
  93. /**
  94. * @deprecated Use getValue which returns a Blob.
  95. */
  96. Object.defineProperty(Name.Component.prototype, "value",
  97. { get: function() { return this.getValueAsBuffer(); } });
  98. /**
  99. * Convert this component value to a string by escaping characters according to the NDN URI Scheme.
  100. * This also adds "..." to a value with zero or more ".".
  101. * @returns {string} The escaped string.
  102. */
  103. Name.Component.prototype.toEscapedString = function()
  104. {
  105. return Name.toEscapedString(this.value_.buf());
  106. };
  107. /**
  108. * Check if this component is a segment number according to NDN naming
  109. * conventions for "Segment number" (marker 0x00).
  110. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  111. * @returns {number} True if this is a segment number.
  112. */
  113. Name.Component.prototype.isSegment = function()
  114. {
  115. return this.value_.size() >= 1 && this.value_.buf()[0] == 0x00;
  116. };
  117. /**
  118. * Check if this component is a segment byte offset according to NDN
  119. * naming conventions for segment "Byte offset" (marker 0xFB).
  120. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  121. * @returns True if this is a segment byte offset.
  122. */
  123. Name.Component.prototype.isSegmentOffset = function()
  124. {
  125. return this.value_.size() >= 1 && this.value_.buf()[0] == 0xFB;
  126. };
  127. /**
  128. * Check if this component is a version number according to NDN naming
  129. * conventions for "Versioning" (marker 0xFD).
  130. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  131. * @returns {number} True if this is a version number.
  132. */
  133. Name.Component.prototype.isVersion = function()
  134. {
  135. return this.value_.size() >= 1 && this.value_.buf()[0] == 0xFD;
  136. };
  137. /**
  138. * Check if this component is a timestamp according to NDN naming
  139. * conventions for "Timestamp" (marker 0xFC).
  140. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  141. * @returns True if this is a timestamp.
  142. */
  143. Name.Component.prototype.isTimestamp = function()
  144. {
  145. return this.value_.size() >= 1 && this.value_.buf()[0] == 0xFC;
  146. };
  147. /**
  148. * Check if this component is a sequence number according to NDN naming
  149. * conventions for "Sequencing" (marker 0xFE).
  150. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  151. * @returns True if this is a sequence number.
  152. */
  153. Name.Component.prototype.isSequenceNumber = function()
  154. {
  155. return this.value_.size() >= 1 && this.value_.buf()[0] == 0xFE;
  156. };
  157. /**
  158. * Interpret this name component as a network-ordered number and return an integer.
  159. * @returns {number} The integer number.
  160. */
  161. Name.Component.prototype.toNumber = function()
  162. {
  163. return DataUtils.bigEndianToUnsignedInt(this.value_.buf());
  164. };
  165. /**
  166. * Interpret this name component as a network-ordered number with a marker and
  167. * return an integer.
  168. * @param {number} marker The required first byte of the component.
  169. * @returns {number} The integer number.
  170. * @throws Error If the first byte of the component does not equal the marker.
  171. */
  172. Name.Component.prototype.toNumberWithMarker = function(marker)
  173. {
  174. if (this.value_.size() == 0 || this.value_.buf()[0] != marker)
  175. throw new Error("Name component does not begin with the expected marker");
  176. return DataUtils.bigEndianToUnsignedInt(this.value_.buf().slice(1));
  177. };
  178. /**
  179. * Interpret this name component as a segment number according to NDN naming
  180. * conventions for "Segment number" (marker 0x00).
  181. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  182. * @returns {number} The integer segment number.
  183. * @throws Error If the first byte of the component is not the expected marker.
  184. */
  185. Name.Component.prototype.toSegment = function()
  186. {
  187. return this.toNumberWithMarker(0x00);
  188. };
  189. /**
  190. * Interpret this name component as a segment byte offset according to NDN
  191. * naming conventions for segment "Byte offset" (marker 0xFB).
  192. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  193. * @returns The integer segment byte offset.
  194. * @throws Error If the first byte of the component is not the expected marker.
  195. */
  196. Name.Component.prototype.toSegmentOffset = function()
  197. {
  198. return this.toNumberWithMarker(0xFB);
  199. };
  200. /**
  201. * Interpret this name component as a version number according to NDN naming
  202. * conventions for "Versioning" (marker 0xFD). Note that this returns
  203. * the exact number from the component without converting it to a time
  204. * representation.
  205. * @returns {number} The integer version number.
  206. * @throws Error If the first byte of the component is not the expected marker.
  207. */
  208. Name.Component.prototype.toVersion = function()
  209. {
  210. return this.toNumberWithMarker(0xFD);
  211. };
  212. /**
  213. * Interpret this name component as a timestamp according to NDN naming
  214. * conventions for "Timestamp" (marker 0xFC).
  215. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  216. * @returns The number of microseconds since the UNIX epoch (Thursday,
  217. * 1 January 1970) not counting leap seconds.
  218. * @throws Error If the first byte of the component is not the expected marker.
  219. */
  220. Name.Component.prototype.toTimestamp = function()
  221. {
  222. return this.toNumberWithMarker(0xFC);
  223. };
  224. /**
  225. * Interpret this name component as a sequence number according to NDN naming
  226. * conventions for "Sequencing" (marker 0xFE).
  227. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  228. * @returns The integer sequence number.
  229. * @throws Error If the first byte of the component is not the expected marker.
  230. */
  231. Name.Component.prototype.toSequenceNumber = function()
  232. {
  233. return this.toNumberWithMarker(0xFE);
  234. };
  235. /**
  236. * Create a component whose value is the nonNegativeInteger encoding of the
  237. * number.
  238. * @param {number} number
  239. * @returns {Name.Component}
  240. */
  241. Name.Component.fromNumber = function(number)
  242. {
  243. var encoder = new TlvEncoder(8);
  244. encoder.writeNonNegativeInteger(number);
  245. return new Name.Component(new Blob(encoder.getOutput(), false));
  246. };
  247. /**
  248. * Create a component whose value is the marker appended with the
  249. * nonNegativeInteger encoding of the number.
  250. * @param {number} number
  251. * @param {number} marker
  252. * @returns {Name.Component}
  253. */
  254. Name.Component.fromNumberWithMarker = function(number, marker)
  255. {
  256. var encoder = new TlvEncoder(9);
  257. // Encode backwards.
  258. encoder.writeNonNegativeInteger(number);
  259. encoder.writeNonNegativeInteger(marker);
  260. return new Name.Component(new Blob(encoder.getOutput(), false));
  261. };
  262. /**
  263. * Create a component with the encoded segment number according to NDN
  264. * naming conventions for "Segment number" (marker 0x00).
  265. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  266. * param {number} segment The segment number.
  267. * returns {Name.Component} The new Component.
  268. */
  269. Name.Component.fromSegment = function(segment)
  270. {
  271. return Name.Component.fromNumberWithMarker(segment, 0x00);
  272. };
  273. /**
  274. * Create a component with the encoded segment byte offset according to NDN
  275. * naming conventions for segment "Byte offset" (marker 0xFB).
  276. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  277. * param {number} segmentOffset The segment byte offset.
  278. * returns {Name.Component} The new Component.
  279. */
  280. Name.Component.fromSegmentOffset = function(segmentOffset)
  281. {
  282. return Name.Component.fromNumberWithMarker(segmentOffset, 0xFB);
  283. };
  284. /**
  285. * Create a component with the encoded version number according to NDN
  286. * naming conventions for "Versioning" (marker 0xFD).
  287. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  288. * Note that this encodes the exact value of version without converting from a
  289. * time representation.
  290. * param {number} version The version number.
  291. * returns {Name.Component} The new Component.
  292. */
  293. Name.Component.fromVersion = function(version)
  294. {
  295. return Name.Component.fromNumberWithMarker(version, 0xFD);
  296. };
  297. /**
  298. * Create a component with the encoded timestamp according to NDN naming
  299. * conventions for "Timestamp" (marker 0xFC).
  300. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  301. * param {number} timestamp The number of microseconds since the UNIX epoch (Thursday,
  302. * 1 January 1970) not counting leap seconds.
  303. * returns {Name.Component} The new Component.
  304. */
  305. Name.Component.fromTimestamp = function(timestamp)
  306. {
  307. return Name.Component.fromNumberWithMarker(timestamp, 0xFC);
  308. };
  309. /**
  310. * Create a component with the encoded sequence number according to NDN naming
  311. * conventions for "Sequencing" (marker 0xFE).
  312. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  313. * param {number} sequenceNumber The sequence number.
  314. * returns {Name.Component} The new Component.
  315. */
  316. Name.Component.fromSequenceNumber = function(sequenceNumber)
  317. {
  318. return Name.Component.fromNumberWithMarker(sequenceNumber, 0xFE);
  319. };
  320. /**
  321. * Get the successor of this component, as described in Name.getSuccessor.
  322. * @returns {Name.Component} A new Name.Component which is the successor of this.
  323. */
  324. Name.Component.prototype.getSuccessor = function()
  325. {
  326. // Allocate an extra byte in case the result is larger.
  327. var result = new Buffer(this.value_.size() + 1);
  328. var carry = true;
  329. for (var i = this.value_.size() - 1; i >= 0; --i) {
  330. if (carry) {
  331. result[i] = (this.value_.buf()[i] + 1) & 0xff;
  332. carry = (result[i] === 0);
  333. }
  334. else
  335. result[i] = this.value_.buf()[i];
  336. }
  337. if (carry)
  338. // Assume all the bytes were set to zero (or the component was empty). In
  339. // NDN ordering, carry does not mean to prepend a 1, but to make a component
  340. // one byte longer of all zeros.
  341. result[result.length - 1] = 0;
  342. else
  343. // We didn't need the extra byte.
  344. result = result.slice(0, this.value_.size());
  345. return new Name.Component(new Blob(result, false));
  346. };
  347. /**
  348. * Check if this is the same component as other.
  349. * @param {Name.Component} other The other Component to compare with.
  350. * @returns {Boolean} true if the components are equal, otherwise false.
  351. */
  352. Name.Component.prototype.equals = function(other)
  353. {
  354. return typeof other === 'object' && other instanceof Name.Component &&
  355. this.value_.equals(other.value_);
  356. };
  357. /**
  358. * Compare this to the other Component using NDN canonical ordering.
  359. * @param {Name.Component} other The other Component to compare with.
  360. * @returns {number} 0 if they compare equal, -1 if this comes before other in
  361. * the canonical ordering, or 1 if this comes after other in the canonical
  362. * ordering.
  363. *
  364. * @see http://named-data.net/doc/0.2/technical/CanonicalOrder.html
  365. */
  366. Name.Component.prototype.compare = function(other)
  367. {
  368. return Name.Component.compareBuffers(this.value_.buf(), other.value_.buf());
  369. };
  370. /**
  371. * Do the work of Name.Component.compare to compare the component buffers.
  372. * @param {Buffer} component1
  373. * @param {Buffer} component2
  374. * @returns {number} 0 if they compare equal, -1 if component1 comes before
  375. * component2 in the canonical ordering, or 1 if component1 comes after
  376. * component2 in the canonical ordering.
  377. */
  378. Name.Component.compareBuffers = function(component1, component2)
  379. {
  380. if (component1.length < component2.length)
  381. return -1;
  382. if (component1.length > component2.length)
  383. return 1;
  384. for (var i = 0; i < component1.length; ++i) {
  385. if (component1[i] < component2[i])
  386. return -1;
  387. if (component1[i] > component2[i])
  388. return 1;
  389. }
  390. return 0;
  391. };
  392. /**
  393. * @deprecated Use toUri.
  394. */
  395. Name.prototype.getName = function()
  396. {
  397. return this.toUri();
  398. };
  399. /** Parse uri as a URI and return an array of Buffer components.
  400. */
  401. Name.createNameArray = function(uri)
  402. {
  403. uri = uri.trim();
  404. if (uri.length <= 0)
  405. return [];
  406. var iColon = uri.indexOf(':');
  407. if (iColon >= 0) {
  408. // Make sure the colon came before a '/'.
  409. var iFirstSlash = uri.indexOf('/');
  410. if (iFirstSlash < 0 || iColon < iFirstSlash)
  411. // Omit the leading protocol such as ndn:
  412. uri = uri.substr(iColon + 1, uri.length - iColon - 1).trim();
  413. }
  414. if (uri[0] == '/') {
  415. if (uri.length >= 2 && uri[1] == '/') {
  416. // Strip the authority following "//".
  417. var iAfterAuthority = uri.indexOf('/', 2);
  418. if (iAfterAuthority < 0)
  419. // Unusual case: there was only an authority.
  420. return [];
  421. else
  422. uri = uri.substr(iAfterAuthority + 1, uri.length - iAfterAuthority - 1).trim();
  423. }
  424. else
  425. uri = uri.substr(1, uri.length - 1).trim();
  426. }
  427. var array = uri.split('/');
  428. // Unescape the components.
  429. for (var i = 0; i < array.length; ++i) {
  430. var value = Name.fromEscapedString(array[i]);
  431. if (value.isNull()) {
  432. // Ignore the illegal componenent. This also gets rid of a trailing '/'.
  433. array.splice(i, 1);
  434. --i;
  435. continue;
  436. }
  437. else
  438. array[i] = new Name.Component(value);
  439. }
  440. return array;
  441. };
  442. /**
  443. * Parse the uri according to the NDN URI Scheme and set the name with the
  444. * components.
  445. * @param {string} uri The URI string.
  446. */
  447. Name.prototype.set = function(uri)
  448. {
  449. this.components = Name.createNameArray(uri);
  450. ++this.changeCount;
  451. };
  452. /**
  453. * Convert the component to a Buffer and append to this Name.
  454. * Return this Name object to allow chaining calls to add.
  455. * @param {Name.Component|String|Array<number>|ArrayBuffer|Buffer|Name} component If a component is a string, encode as utf8 (but don't unescape).
  456. * @returns {Name}
  457. */
  458. Name.prototype.append = function(component)
  459. {
  460. if (typeof component == 'object' && component instanceof Name) {
  461. var components;
  462. if (component == this)
  463. // special case, when we need to create a copy
  464. components = this.components.slice(0, this.components.length);
  465. else
  466. components = component.components;
  467. for (var i = 0; i < components.length; ++i)
  468. this.components.push(new Name.Component(components[i]));
  469. }
  470. else
  471. // Just use the Name.Component constructor.
  472. this.components.push(new Name.Component(component));
  473. ++this.changeCount;
  474. return this;
  475. };
  476. /**
  477. * @deprecated Use append.
  478. */
  479. Name.prototype.add = function(component)
  480. {
  481. return this.append(component);
  482. };
  483. /**
  484. * Clear all the components.
  485. */
  486. Name.prototype.clear = function()
  487. {
  488. this.components = [];
  489. ++this.changeCount;
  490. };
  491. /**
  492. * Return the escaped name string according to NDN URI Scheme.
  493. * @param {boolean} includeScheme (optional) If true, include the "ndn:" scheme
  494. * in the URI, e.g. "ndn:/example/name". If false, just return the path, e.g.
  495. * "/example/name". If ommitted, then just return the path which is the default
  496. * case where toUri() is used for display.
  497. * @returns {String}
  498. */
  499. Name.prototype.toUri = function(includeScheme)
  500. {
  501. if (this.size() == 0)
  502. return includeScheme ? "ndn:/" : "/";
  503. var result = includeScheme ? "ndn:" : "";
  504. for (var i = 0; i < this.size(); ++i)
  505. result += "/"+ Name.toEscapedString(this.components[i].getValue().buf());
  506. return result;
  507. };
  508. /**
  509. * @deprecated Use toUri.
  510. */
  511. Name.prototype.to_uri = function()
  512. {
  513. return this.toUri();
  514. };
  515. Name.prototype.toString = function() { return this.toUri(); }
  516. /**
  517. * Append a component with the encoded segment number according to NDN
  518. * naming conventions for "Segment number" (marker 0x00).
  519. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  520. * @param {number} segment The segment number.
  521. * @returns {Name} This name so that you can chain calls to append.
  522. */
  523. Name.prototype.appendSegment = function(segment)
  524. {
  525. return this.append(Name.Component.fromSegment(segment));
  526. };
  527. /**
  528. * Append a component with the encoded segment byte offset according to NDN
  529. * naming conventions for segment "Byte offset" (marker 0xFB).
  530. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  531. * @param {number} segmentOffset The segment byte offset.
  532. * @returns {Name} This name so that you can chain calls to append.
  533. */
  534. Name.prototype.appendSegmentOffset = function(segmentOffset)
  535. {
  536. return this.append(Name.Component.fromSegmentOffset(segmentOffset));
  537. };
  538. /**
  539. * Append a component with the encoded version number according to NDN
  540. * naming conventions for "Versioning" (marker 0xFD).
  541. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  542. * Note that this encodes the exact value of version without converting from a time representation.
  543. * @param {number} version The version number.
  544. * @returns {Name} This name so that you can chain calls to append.
  545. */
  546. Name.prototype.appendVersion = function(version)
  547. {
  548. return this.append(Name.Component.fromVersion(version));
  549. };
  550. /**
  551. * Append a component with the encoded timestamp according to NDN naming
  552. * conventions for "Timestamp" (marker 0xFC).
  553. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  554. * @param {number} timestamp The number of microseconds since the UNIX epoch (Thursday,
  555. * 1 January 1970) not counting leap seconds.
  556. * @returns This name so that you can chain calls to append.
  557. */
  558. Name.prototype.appendTimestamp = function(timestamp)
  559. {
  560. return this.append(Name.Component.fromTimestamp(timestamp));
  561. };
  562. /**
  563. * Append a component with the encoded sequence number according to NDN naming
  564. * conventions for "Sequencing" (marker 0xFE).
  565. * http://named-data.net/doc/tech-memos/naming-conventions.pdf
  566. * @param {number} sequenceNumber The sequence number.
  567. * @returns This name so that you can chain calls to append.
  568. */
  569. Name.prototype.appendSequenceNumber = function(sequenceNumber)
  570. {
  571. return this.append(Name.Component.fromSequenceNumber(sequenceNumber));
  572. };
  573. /**
  574. * @deprecated Use appendSegment.
  575. */
  576. Name.prototype.addSegment = function(number)
  577. {
  578. return this.appendSegment(number);
  579. };
  580. /**
  581. * Get a new name, constructed as a subset of components.
  582. * @param {number} iStartComponent The index if the first component to get. If
  583. * iStartComponent is -N then return return components starting from
  584. * name.size() - N.
  585. * @param {number} (optional) nComponents The number of components starting at
  586. * iStartComponent. If omitted or greater than the size of this name, get until
  587. * the end of the name.
  588. * @returns {Name} A new name.
  589. */
  590. Name.prototype.getSubName = function(iStartComponent, nComponents)
  591. {
  592. if (iStartComponent < 0)
  593. iStartComponent = this.components.length - (-iStartComponent);
  594. if (nComponents == undefined)
  595. nComponents = this.components.length - iStartComponent;
  596. var result = new Name();
  597. var iEnd = iStartComponent + nComponents;
  598. for (var i = iStartComponent; i < iEnd && i < this.components.length; ++i)
  599. result.components.push(this.components[i]);
  600. return result;
  601. };
  602. /**
  603. * Return a new Name with the first nComponents components of this Name.
  604. * @param {number} nComponents The number of prefix components. If nComponents is -N then return the prefix up
  605. * to name.size() - N. For example getPrefix(-1) returns the name without the final component.
  606. * @returns {Name} A new name.
  607. */
  608. Name.prototype.getPrefix = function(nComponents)
  609. {
  610. if (nComponents < 0)
  611. return this.getSubName(0, this.components.length + nComponents);
  612. else
  613. return this.getSubName(0, nComponents);
  614. };
  615. /**
  616. * @deprecated Use getPrefix(-nComponents).
  617. */
  618. Name.prototype.cut = function(nComponents)
  619. {
  620. return new Name(this.components.slice(0, this.components.length - nComponents));
  621. };
  622. /**
  623. * Return the number of name components.
  624. * @returns {number}
  625. */
  626. Name.prototype.size = function()
  627. {
  628. return this.components.length;
  629. };
  630. /**
  631. * Get a Name Component by index number.
  632. * @param {Number} i The index of the component, starting from 0. However, if i is negative, return the component
  633. * at size() - (-i).
  634. * @returns {Name.Component}
  635. */
  636. Name.prototype.get = function(i)
  637. {
  638. if (i >= 0) {
  639. if (i >= this.components.length)
  640. throw new Error("Name.get: Index is out of bounds");
  641. return new Name.Component(this.components[i]);
  642. }
  643. else {
  644. // Negative index.
  645. if (i < -this.components.length)
  646. throw new Error("Name.get: Index is out of bounds");
  647. return new Name.Component(this.components[this.components.length - (-i)]);
  648. }
  649. };
  650. /**
  651. * @deprecated Use size().
  652. */
  653. Name.prototype.getComponentCount = function()
  654. {
  655. return this.components.length;
  656. };
  657. /**
  658. * @deprecated To get just the component value array, use get(i).getValue().buf().
  659. */
  660. Name.prototype.getComponent = function(i)
  661. {
  662. return new Buffer(this.components[i].getValue().buf());
  663. };
  664. /**
  665. * The "file name" in a name is the last component that isn't blank and doesn't start with one of the
  666. * special marker octets (for version, etc.). Return the index in this.components of
  667. * the file name, or -1 if not found.
  668. */
  669. Name.prototype.indexOfFileName = function()
  670. {
  671. for (var i = this.size() - 1; i >= 0; --i) {
  672. var component = this.components[i].getValue().buf();
  673. if (component.length <= 0)
  674. continue;
  675. if (component[0] == 0 || component[0] == 0xC0 || component[0] == 0xC1 ||
  676. (component[0] >= 0xF5 && component[0] <= 0xFF))
  677. continue;
  678. return i;
  679. }
  680. return -1;
  681. };
  682. /**
  683. * Encode this Name for a particular wire format.
  684. * @param {WireFormat} wireFormat (optional) A WireFormat object used to encode
  685. * this object. If omitted, use WireFormat.getDefaultWireFormat().
  686. * @returns {Blob} The encoded buffer in a Blob object.
  687. */
  688. Name.prototype.wireEncode = function(wireFormat)
  689. {
  690. wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
  691. return wireFormat.encodeName(this);
  692. };
  693. /**
  694. * Decode the input using a particular wire format and update this Name.
  695. * @param {Blob|Buffer} input The buffer with the bytes to decode.
  696. * @param {WireFormat} wireFormat (optional) A WireFormat object used to decode
  697. * this object. If omitted, use WireFormat.getDefaultWireFormat().
  698. */
  699. Name.prototype.wireDecode = function(input, wireFormat)
  700. {
  701. wireFormat = (wireFormat || WireFormat.getDefaultWireFormat());
  702. // If input is a blob, get its buf().
  703. var decodeBuffer = typeof input === 'object' && input instanceof Blob ?
  704. input.buf() : input;
  705. wireFormat.decodeName(this, decodeBuffer);
  706. };
  707. /**
  708. * Compare this to the other Name using NDN canonical ordering. If the first
  709. * components of each name are not equal, this returns -1 if the first comes
  710. * before the second using the NDN canonical ordering for name components, or 1
  711. * if it comes after. If they are equal, this compares the second components of
  712. * each name, etc. If both names are the same up to the size of the shorter
  713. * name, this returns -1 if the first name is shorter than the second or 1 if it
  714. * is longer. For example, std::sort gives: /a/b/d /a/b/cc /c /c/a /bb . This
  715. * is intuitive because all names with the prefix /a are next to each other.
  716. * But it may be also be counter-intuitive because /c comes before /bb according
  717. * to NDN canonical ordering since it is shorter.
  718. * @param {Name} other The other Name to compare with.
  719. * @returns {boolean} If they compare equal, -1 if *this comes before other in
  720. * the canonical ordering, or 1 if *this comes after other in the canonical
  721. * ordering. The first form of compare is simply compare(other). The second form is
  722. * compare(iStartComponent, nComponents, other [, iOtherStartComponent] [, nOtherComponents])
  723. * which is equivalent to
  724. * self.getSubName(iStartComponent, nComponents).compare
  725. * (other.getSubName(iOtherStartComponent, nOtherComponents)) .
  726. * @param {number} iStartComponent The index if the first component of this name
  727. * to get. If iStartComponent is -N then compare components starting from
  728. * name.size() - N.
  729. * @param {number} nComponents The number of components starting at
  730. * iStartComponent. If greater than the size of this name, compare until the end
  731. * of the name.
  732. * @param {Name other: The other Name to compare with.
  733. * @param {number} iOtherStartComponent (optional) The index if the first
  734. * component of the other name to compare. If iOtherStartComponent is -N then
  735. * compare components starting from other.size() - N. If omitted, compare
  736. * starting from index 0.
  737. * @param {number} nOtherComponents (optional) The number of components
  738. * starting at iOtherStartComponent. If omitted or greater than the size of this
  739. * name, compare until the end of the name.
  740. * @returns {number} 0 If they compare equal, -1 if self comes before other in
  741. * the canonical ordering, or 1 if self comes after other in the canonical
  742. * ordering.
  743. * @see http://named-data.net/doc/0.2/technical/CanonicalOrder.html
  744. */
  745. Name.prototype.compare = function
  746. (iStartComponent, nComponents, other, iOtherStartComponent, nOtherComponents)
  747. {
  748. if (iStartComponent instanceof Name) {
  749. // compare(other)
  750. other = iStartComponent;
  751. iStartComponent = 0;
  752. nComponents = this.size();
  753. }
  754. if (iOtherStartComponent == undefined)
  755. iOtherStartComponent = 0;
  756. if (nOtherComponents == undefined)
  757. nOtherComponents = other.size();
  758. if (iStartComponent < 0)
  759. iStartComponent = this.size() - (-iStartComponent);
  760. if (iOtherStartComponent < 0)
  761. iOtherStartComponent = other.size() - (-iOtherStartComponent);
  762. nComponents = Math.min(nComponents, this.size() - iStartComponent);
  763. nOtherComponents = Math.min(nOtherComponents, other.size() - iOtherStartComponent);
  764. var count = Math.min(nComponents, nOtherComponents);
  765. for (var i = 0; i < count; ++i) {
  766. var comparison = this.components[iStartComponent + i].compare
  767. (other.components[iOtherStartComponent + i]);
  768. if (comparison == 0)
  769. // The components at this index are equal, so check the next components.
  770. continue;
  771. // Otherwise, the result is based on the components at this index.
  772. return comparison;
  773. }
  774. // The components up to min(this.size(), other.size()) are equal, so the
  775. // shorter name is less.
  776. if (nComponents < nOtherComponents)
  777. return -1;
  778. else if (nComponents > nOtherComponents)
  779. return 1;
  780. else
  781. return 0;
  782. };
  783. /**
  784. * Return true if this Name has the same components as name.
  785. */
  786. Name.prototype.equals = function(name)
  787. {
  788. if (this.components.length != name.components.length)
  789. return false;
  790. // Start from the last component because they are more likely to differ.
  791. for (var i = this.components.length - 1; i >= 0; --i) {
  792. if (!this.components[i].equals(name.components[i]))
  793. return false;
  794. }
  795. return true;
  796. };
  797. /**
  798. * @deprecated Use equals.
  799. */
  800. Name.prototype.equalsName = function(name)
  801. {
  802. return this.equals(name);
  803. };
  804. /**
  805. * Find the last component in name that has a ContentDigest and return the digest value as Buffer,
  806. * or null if not found. See Name.getComponentContentDigestValue.
  807. */
  808. Name.prototype.getContentDigestValue = function()
  809. {
  810. for (var i = this.size() - 1; i >= 0; --i) {
  811. var digestValue = Name.getComponentContentDigestValue(this.components[i]);
  812. if (digestValue != null)
  813. return digestValue;
  814. }
  815. return null;
  816. };
  817. /**
  818. * If component is a ContentDigest, return the digest value as a Buffer slice (don't modify!).
  819. * If not a ContentDigest, return null.
  820. * A ContentDigest component is Name.ContentDigestPrefix + 32 bytes + Name.ContentDigestSuffix.
  821. */
  822. Name.getComponentContentDigestValue = function(component)
  823. {
  824. if (typeof component == 'object' && component instanceof Name.Component)
  825. component = component.getValue().buf();
  826. var digestComponentLength = Name.ContentDigestPrefix.length + 32 + Name.ContentDigestSuffix.length;
  827. // Check for the correct length and equal ContentDigestPrefix and ContentDigestSuffix.
  828. if (component.length == digestComponentLength &&
  829. DataUtils.arraysEqual(component.slice(0, Name.ContentDigestPrefix.length),
  830. Name.ContentDigestPrefix) &&
  831. DataUtils.arraysEqual(component.slice
  832. (component.length - Name.ContentDigestSuffix.length, component.length),
  833. Name.ContentDigestSuffix))
  834. return component.slice(Name.ContentDigestPrefix.length, Name.ContentDigestPrefix.length + 32);
  835. else
  836. return null;
  837. };
  838. // Meta GUID "%C1.M.G%C1" + ContentDigest with a 32 byte BLOB.
  839. Name.ContentDigestPrefix = new Buffer([0xc1, 0x2e, 0x4d, 0x2e, 0x47, 0xc1, 0x01, 0xaa, 0x02, 0x85]);
  840. Name.ContentDigestSuffix = new Buffer([0x00]);
  841. /**
  842. * Return value as an escaped string according to NDN URI Scheme.
  843. * We can't use encodeURIComponent because that doesn't encode all the characters we want to.
  844. * @param {Buffer|Name.Component} component The value or Name.Component to escape.
  845. * @returns {string} The escaped string.
  846. */
  847. Name.toEscapedString = function(value)
  848. {
  849. if (typeof value == 'object' && value instanceof Name.Component)
  850. value = value.getValue().buf();
  851. else if (typeof value === 'object' && value instanceof Blob)
  852. value = value.buf();
  853. var result = "";
  854. var gotNonDot = false;
  855. for (var i = 0; i < value.length; ++i) {
  856. if (value[i] != 0x2e) {
  857. gotNonDot = true;
  858. break;
  859. }
  860. }
  861. if (!gotNonDot) {
  862. // Special case for component of zero or more periods. Add 3 periods.
  863. result = "...";
  864. for (var i = 0; i < value.length; ++i)
  865. result += ".";
  866. }
  867. else {
  868. for (var i = 0; i < value.length; ++i) {
  869. var x = value[i];
  870. // Check for 0-9, A-Z, a-z, (+), (-), (.), (_)
  871. if (x >= 0x30 && x <= 0x39 || x >= 0x41 && x <= 0x5a ||
  872. x >= 0x61 && x <= 0x7a || x == 0x2b || x == 0x2d ||
  873. x == 0x2e || x == 0x5f)
  874. result += String.fromCharCode(x);
  875. else
  876. result += "%" + (x < 16 ? "0" : "") + x.toString(16).toUpperCase();
  877. }
  878. }
  879. return result;
  880. };
  881. /**
  882. * Make a blob value by decoding the escapedString according to NDN URI Scheme.
  883. * If escapedString is "", "." or ".." then return null, which means to skip the component in the name.
  884. * @param {string} escapedString The escaped string to decode.
  885. * @returns {Blob} The unescaped Blob value. If the escapedString is not a valid
  886. * escaped component, then the Blob isNull().
  887. */
  888. Name.fromEscapedString = function(escapedString)
  889. {
  890. var value = unescape(escapedString.trim());
  891. if (value.match(/[^.]/) == null) {
  892. // Special case for value of only periods.
  893. if (value.length <= 2)
  894. // Zero, one or two periods is illegal. Ignore this componenent to be
  895. // consistent with the C implementation.
  896. return new Blob();
  897. else
  898. // Remove 3 periods.
  899. return new Blob
  900. (DataUtils.toNumbersFromString(value.substr(3, value.length - 3)), false);
  901. }
  902. else
  903. return new Blob(DataUtils.toNumbersFromString(value), false);
  904. };
  905. /**
  906. * @deprecated Use fromEscapedString. This method returns a Buffer which is the former
  907. * behavior of fromEscapedString, and should only be used while updating your code.
  908. */
  909. Name.fromEscapedStringAsBuffer = function(escapedString)
  910. {
  911. return Name.fromEscapedString(escapedString).buf();
  912. };
  913. /**
  914. * Get the successor of this name which is defined as follows.
  915. *
  916. * N represents the set of NDN Names, and X,Y ∈ N.
  917. * Operator < is defined by the NDN canonical order on N.
  918. * Y is the successor of X, if (a) X < Y, and (b) ∄ Z ∈ N s.t. X < Z < Y.
  919. *
  920. * In plain words, the successor of a name is the same name, but with its last
  921. * component advanced to a next possible value.
  922. *
  923. * Examples:
  924. *
  925. * - The successor of / is /%00
  926. * - The successor of /%00%01/%01%02 is /%00%01/%01%03
  927. * - The successor of /%00%01/%01%FF is /%00%01/%02%00
  928. * - The successor of /%00%01/%FF%FF is /%00%01/%00%00%00
  929. *
  930. * @returns {Name} A new name which is the successor of this.
  931. */
  932. Name.prototype.getSuccessor = function()
  933. {
  934. if (this.size() == 0) {
  935. // Return "/%00".
  936. var result = new Name();
  937. result.append(new Blob(new Buffer([0]), false));
  938. return result;
  939. }
  940. else
  941. return this.getPrefix(-1).append(this.get(-1).getSuccessor());
  942. };
  943. /**
  944. * Return true if the N components of this name are the same as the first N
  945. * components of the given name.
  946. * @param {Name} name The name to check.
  947. * @returns {Boolean} true if this matches the given name. This always returns
  948. * true if this name is empty.
  949. */
  950. Name.prototype.match = function(name)
  951. {
  952. var i_name = this.components;
  953. var o_name = name.components;
  954. // This name is longer than the name we are checking it against.
  955. if (i_name.length > o_name.length)
  956. return false;
  957. // Check if at least one of given components doesn't match. Check from last to
  958. // first since the last components are more likely to differ.
  959. for (var i = i_name.length - 1; i >= 0; --i) {
  960. if (!i_name[i].equals(o_name[i]))
  961. return false;
  962. }
  963. return true;
  964. };
  965. /**
  966. * Return true if the N components of this name are the same as the first N
  967. * components of the given name.
  968. * @param {Name} name The name to check.
  969. * @returns {Boolean} true if this matches the given name. This always returns
  970. * true if this name is empty.
  971. */
  972. Name.prototype.isPrefixOf = function(name) { return this.match(name); }
  973. /**
  974. * Get the change count, which is incremented each time this object is changed.
  975. * @returns {number} The change count.
  976. */
  977. Name.prototype.getChangeCount = function()
  978. {
  979. return this.changeCount;
  980. };
  981. // Put these requires at the bottom to avoid circular references.
  982. var TlvEncoder = require('./encoding/tlv/tlv-encoder.js').TlvEncoder;
  983. var WireFormat = require('./encoding/wire-format.js').WireFormat;