ndn-js
Version:
A JavaScript client library for Named Data Networking
1,302 lines (1,126 loc) • 60.1 kB
JavaScript
/**
* Copyright (C) 2021 Regents of the University of California.
* @author: Jeff Thompson <jefft0@remap.ucla.edu>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU Lesser General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
* A copy of the GNU Lesser General Public License is in the file COPYING.
*/
/** @ignore */
var Crypto = require('../crypto.js'); /** @ignore */
var Blob = require('../util/blob.js').Blob; /** @ignore */
var Name = require('../name.js').Name; /** @ignore */
var ComponentType = require('../name.js').ComponentType; /** @ignore */
var RegistrationOptions = require('../registration-options').RegistrationOptions; /** @ignore */
var Tlv = require('./tlv/tlv.js').Tlv; /** @ignore */
var TlvEncoder = require('./tlv/tlv-encoder.js').TlvEncoder; /** @ignore */
var TlvDecoder = require('./tlv/tlv-decoder.js').TlvDecoder; /** @ignore */
var WireFormat = require('./wire-format.js').WireFormat; /** @ignore */
var Exclude = require('../exclude.js').Exclude; /** @ignore */
var ContentType = require('../meta-info.js').ContentType; /** @ignore */
var KeyLocatorType = require('../key-locator.js').KeyLocatorType; /** @ignore */
var Sha256WithRsaSignature = require('../sha256-with-rsa-signature.js').Sha256WithRsaSignature; /** @ignore */
var Sha256WithEcdsaSignature = require('../sha256-with-ecdsa-signature.js').Sha256WithEcdsaSignature; /** @ignore */
var GenericSignature = require('../generic-signature.js').GenericSignature; /** @ignore */
var HmacWithSha256Signature = require('../hmac-with-sha256-signature.js').HmacWithSha256Signature; /** @ignore */
var DigestSha256Signature = require('../digest-sha256-signature.js').DigestSha256Signature; /** @ignore */
var ControlParameters = require('../control-parameters.js').ControlParameters; /** @ignore */
var NetworkNack = require('../network-nack.js').NetworkNack; /** @ignore */
var Schedule = require('../encrypt/schedule.js').Schedule; /** @ignore */
var IncomingFaceId = require('../lp/incoming-face-id.js').IncomingFaceId; /** @ignore */
var CongestionMark = require('../lp/congestion-mark.js').CongestionMark; /** @ignore */
var DecodingException = require('./decoding-exception.js').DecodingException;
/**
* A Tlv0_3WireFormat implements the WireFormat interface for encoding and
* decoding with the NDN-TLV wire format, version 0.3.
* @constructor
*/
var Tlv0_3WireFormat = function Tlv0_3WireFormat()
{
// Inherit from WireFormat.
WireFormat.call(this);
};
Tlv0_3WireFormat.prototype = new WireFormat();
Tlv0_3WireFormat.prototype.name = "Tlv0_3WireFormat";
exports.Tlv0_3WireFormat = Tlv0_3WireFormat;
// Default object.
Tlv0_3WireFormat.instance = null;
Tlv0_3WireFormat.didCanBePrefixWarning_ = false;
/**
* Encode name as an NDN-TLV Name and return the encoding.
* @param {Name} name The Name to encode.
* @return {Blobl} A Blob containing the encoding.
*/
Tlv0_3WireFormat.prototype.encodeName = function(name)
{
var encoder = new TlvEncoder();
Tlv0_3WireFormat.encodeName(name, encoder);
return new Blob(encoder.getOutput(), false);
};
/**
* Decode input as a NDN-TLV name and set the fields of the Name object.
* @param {Name} name The Name object whose fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
*/
Tlv0_3WireFormat.prototype.decodeName = function(name, input, copy)
{
if (copy == null)
copy = true;
var decoder = new TlvDecoder(input);
Tlv0_3WireFormat.decodeName(name, decoder, copy);
};
/**
* Encode the interest using NDN-TLV and return a Buffer.
* @param {Interest} interest The Interest object to encode.
* @return {object} An associative array with fields
* (encoding, signedPortionBeginOffset, signedPortionEndOffset) where encoding
* is a Blob containing the encoding, signedPortionBeginOffset is the offset in
* the encoding of the beginning of the signed portion, and
* signedPortionEndOffset is the offset in the encoding of the end of the signed
* portion. The signed portion starts from the first name component and ends
* just before the final name component (which is assumed to be a signature for
* a signed interest).
*/
Tlv0_3WireFormat.prototype.encodeInterest = function(interest)
{
if (!interest.didSetCanBePrefix_ && !Tlv0_3WireFormat.didCanBePrefixWarning_) {
console.log
("WARNING: The default CanBePrefix will change. See Interest.setDefaultCanBePrefix() for details.");
Tlv0_3WireFormat.didCanBePrefixWarning_ = true;
}
return Tlv0_3WireFormat.encodeInterestV03_(interest);
};
/**
* Decode input as an NDN-TLV interest and set the fields of the interest
* object.
* @param {Interest} interest The Interest object whose fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
* @return {object} An associative array with fields
* (signedPortionBeginOffset, signedPortionEndOffset) where
* signedPortionBeginOffset is the offset in the encoding of the beginning of
* the signed portion, and signedPortionEndOffset is the offset in the encoding
* of the end of the signed portion. The signed portion starts from the first
* name component and ends just before the final name component (which is
* assumed to be a signature for a signed interest).
*/
Tlv0_3WireFormat.prototype.decodeInterest = function(interest, input, copy)
{
try {
return Tlv0_3WireFormat.decodeInterestV03_(interest, input, copy);
} catch (exceptionV03) {
try {
// Failed to decode as format v0.3. Try to decode as v0.2.
return this.decodeInterestV02_(interest, input, copy);
} catch (ex) {
// Ignore the exception decoding as format v0.2 and throw the exception
// from trying to decode as format as format v0.3.
throw exceptionV03;
}
}
};
/**
* Do the work of decodeInterest to decode strictly as format v0.2.
*/
Tlv0_3WireFormat.prototype.decodeInterestV02_ = function(interest, input, copy)
{
if (copy == null)
copy = true;
var decoder = new TlvDecoder(input);
var endOffset = decoder.readNestedTlvsStart(Tlv.Interest);
var offsets = Tlv0_3WireFormat.decodeName(interest.getName(), decoder, copy);
if (decoder.peekType(Tlv.Selectors, endOffset))
Tlv0_3WireFormat.decodeSelectors(interest, decoder, copy);
else {
// Set selectors to none.
interest.setMinSuffixComponents(null);
interest.setMaxSuffixComponents(null);
interest.getKeyLocator().clear();
interest.getExclude().clear();
interest.setChildSelector(null);
interest.setMustBeFresh(false);
}
// Require a Nonce, but don't force it to be 4 bytes.
var nonce = decoder.readBlobTlv(Tlv.Nonce);
interest.setInterestLifetimeMilliseconds
(decoder.readOptionalNonNegativeIntegerTlv(Tlv.InterestLifetime, endOffset));
if (decoder.peekType(Tlv.ForwardingHint, endOffset)) {
var forwardingHintEndOffset = decoder.readNestedTlvsStart
(Tlv.ForwardingHint);
Tlv0_3WireFormat.decodeDelegationSet_
(interest.getForwardingHint(), forwardingHintEndOffset, decoder, copy);
decoder.finishNestedTlvs(forwardingHintEndOffset);
}
if (decoder.peekType(Tlv.Data, endOffset)) {
// Get the bytes of the Link TLV.
var linkBeginOffset = decoder.getOffset();
var linkEndOffset = decoder.readNestedTlvsStart(Tlv.Data);
decoder.seek(linkEndOffset);
interest.setLinkWireEncoding
(new Blob(decoder.getSlice(linkBeginOffset, linkEndOffset), copy), this);
}
else
interest.unsetLink();
interest.setSelectedDelegationIndex
(decoder.readOptionalNonNegativeIntegerTlv(Tlv.SelectedDelegation, endOffset));
if (interest.getSelectedDelegationIndex() != null &&
interest.getSelectedDelegationIndex() >= 0 && !interest.hasLink())
throw new Error("Interest has a selected delegation, but no link object");
// Format v0.2 doesn't have application parameters.
interest.setApplicationParameters(new Blob());
// Set the nonce last because setting other interest fields clears it.
interest.setNonce(new Blob(nonce, copy));
decoder.finishNestedTlvs(endOffset);
return offsets;
};
/**
* Encode data as NDN-TLV and return the encoding and signed offsets.
* @param {Data} data The Data object to encode.
* @return {object} An associative array with fields
* (encoding, signedPortionBeginOffset, signedPortionEndOffset) where encoding
* is a Blob containing the encoding, signedPortionBeginOffset is the offset in
* the encoding of the beginning of the signed portion, and
* signedPortionEndOffset is the offset in the encoding of the end of the
* signed portion.
*/
Tlv0_3WireFormat.prototype.encodeData = function(data)
{
var encoder = new TlvEncoder(1500);
var saveLength = encoder.getLength();
// Encode backwards.
encoder.writeBlobTlv(Tlv.SignatureValue, data.getSignature().getSignature().buf());
var signedPortionEndOffsetFromBack = encoder.getLength();
Tlv0_3WireFormat.encodeSignatureInfo_(data.getSignature(), encoder);
encoder.writeBlobTlv(Tlv.Content, data.getContent().buf());
Tlv0_3WireFormat.encodeMetaInfo(data.getMetaInfo(), encoder);
Tlv0_3WireFormat.encodeName(data.getName(), encoder);
var signedPortionBeginOffsetFromBack = encoder.getLength();
encoder.writeTypeAndLength(Tlv.Data, encoder.getLength() - saveLength);
var signedPortionBeginOffset =
encoder.getLength() - signedPortionBeginOffsetFromBack;
var signedPortionEndOffset = encoder.getLength() - signedPortionEndOffsetFromBack;
return { encoding: new Blob(encoder.getOutput(), false),
signedPortionBeginOffset: signedPortionBeginOffset,
signedPortionEndOffset: signedPortionEndOffset };
};
/**
* Decode input as an NDN-TLV data packet, set the fields in the data object,
* and return the signed offsets.
* @param {Data} data The Data object whose fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
* @return {object} An associative array with fields
* (signedPortionBeginOffset, signedPortionEndOffset) where
* signedPortionBeginOffset is the offset in the encoding of the beginning of
* the signed portion, and signedPortionEndOffset is the offset in the encoding
* of the end of the signed portion.
*/
Tlv0_3WireFormat.prototype.decodeData = function(data, input, copy)
{
if (copy == null)
copy = true;
var decoder = new TlvDecoder(input);
var endOffset = decoder.readNestedTlvsStart(Tlv.Data);
var signedPortionBeginOffset = decoder.getOffset();
Tlv0_3WireFormat.decodeName(data.getName(), decoder, copy);
if (decoder.peekType(Tlv.MetaInfo, endOffset))
Tlv0_3WireFormat.decodeMetaInfo(data.getMetaInfo(), decoder, copy);
else
data.getMetaInfo().clear();
data.setContent(new Blob(decoder.readOptionalBlobTlv(Tlv.Content, endOffset), copy));
Tlv0_3WireFormat.decodeSignatureInfo(data, decoder, copy);
var signedPortionEndOffset = decoder.getOffset();
data.getSignature().setSignature
(new Blob(decoder.readBlobTlv(Tlv.SignatureValue), copy));
decoder.finishNestedTlvs(endOffset);
return { signedPortionBeginOffset: signedPortionBeginOffset,
signedPortionEndOffset: signedPortionEndOffset };
};
/**
* Encode controlParameters as NDN-TLV and return the encoding.
* @param {ControlParameters} controlParameters The ControlParameters object to
* encode.
* @return {Blob} A Blob containing the encoding.
*/
Tlv0_3WireFormat.prototype.encodeControlParameters = function(controlParameters)
{
var encoder = new TlvEncoder(256);
Tlv0_3WireFormat.encodeControlParameters(controlParameters, encoder);
return new Blob(encoder.getOutput(), false);
};
/**
* Decode controlParameters in NDN-TLV and set the fields of the
* controlParameters object.
* @param {ControlParameters} controlParameters The ControlParameters object
* whose fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
* @throws DecodingException For invalid encoding
*/
Tlv0_3WireFormat.prototype.decodeControlParameters = function
(controlParameters, input, copy)
{
if (copy == null)
copy = true;
var decoder = new TlvDecoder(input);
Tlv0_3WireFormat.decodeControlParameters(controlParameters, decoder, copy);
};
/**
* Encode controlResponse as NDN-TLV and return the encoding.
* @param {ControlResponse} controlResponse The ControlResponse object to
* encode.
* @return {Blob} A Blob containing the encoding.
*/
Tlv0_3WireFormat.prototype.encodeControlResponse = function(controlResponse)
{
var encoder = new TlvEncoder(256);
var saveLength = encoder.getLength();
// Encode backwards.
// Encode the body.
if (controlResponse.getBodyAsControlParameters() != null)
Tlv0_3WireFormat.encodeControlParameters
(controlResponse.getBodyAsControlParameters(), encoder);
encoder.writeBlobTlv
(Tlv.NfdCommand_StatusText, new Blob(controlResponse.getStatusText()).buf());
encoder.writeNonNegativeIntegerTlv
(Tlv.NfdCommand_StatusCode, controlResponse.getStatusCode());
encoder.writeTypeAndLength
(Tlv.NfdCommand_ControlResponse, encoder.getLength() - saveLength);
return new Blob(encoder.getOutput(), false);
};
/**
* Decode controlResponse in NDN-TLV and set the fields of the controlResponse
* object
* @param {ControlResponse} controlResponse The ControlResponse object whose
* fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
* @throws DecodingException For invalid encoding
*/
Tlv0_3WireFormat.prototype.decodeControlResponse = function
(controlResponse, input, copy)
{
if (copy == null)
copy = true;
var decoder = new TlvDecoder(input);
var endOffset = decoder.readNestedTlvsStart(Tlv.NfdCommand_ControlResponse);
controlResponse.setStatusCode(decoder.readNonNegativeIntegerTlv
(Tlv.NfdCommand_StatusCode));
// Set copy false since we just immediately get a string.
var statusText = new Blob
(decoder.readBlobTlv(Tlv.NfdCommand_StatusText), false);
controlResponse.setStatusText(statusText.toString());
// Decode the body.
if (decoder.peekType(Tlv.ControlParameters_ControlParameters, endOffset)) {
controlResponse.setBodyAsControlParameters(new ControlParameters());
// Decode into the existing ControlParameters to avoid copying.
Tlv0_3WireFormat.decodeControlParameters
(controlResponse.getBodyAsControlParameters(), decoder, copy);
}
else
controlResponse.setBodyAsControlParameters(null);
decoder.finishNestedTlvs(endOffset);
};
/**
* Encode signature as an NDN-TLV SignatureInfo and return the encoding.
* @param {Signature} signature An object of a subclass of Signature to encode.
* @return {Blob} A Blob containing the encoding.
*/
Tlv0_3WireFormat.prototype.encodeSignatureInfo = function(signature)
{
var encoder = new TlvEncoder(256);
Tlv0_3WireFormat.encodeSignatureInfo_(signature, encoder);
return new Blob(encoder.getOutput(), false);
};
// SignatureHolder is used by decodeSignatureInfoAndValue.
Tlv0_3WireFormat.SignatureHolder = function Tlv0_3WireFormatSignatureHolder()
{
};
Tlv0_3WireFormat.SignatureHolder.prototype.setSignature = function(signature)
{
this.signature = signature;
};
Tlv0_3WireFormat.SignatureHolder.prototype.getSignature = function()
{
return this.signature;
};
/**
* Decode signatureInfo as an NDN-TLV SignatureInfo and signatureValue as the
* related SignatureValue, and return a new object which is a subclass of Signature.
* @param {Buffer} signatureInfo The buffer with the signature info bytes to
* decode.
* @param {Buffer} signatureValue The buffer with the signature value to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
* @return {Signature} A new object which is a subclass of Signature.
*/
Tlv0_3WireFormat.prototype.decodeSignatureInfoAndValue = function
(signatureInfo, signatureValue, copy)
{
if (copy == null)
copy = true;
// Use a SignatureHolder to imitate a Data object for decodeSignatureInfo.
var signatureHolder = new Tlv0_3WireFormat.SignatureHolder();
var decoder = new TlvDecoder(signatureInfo);
Tlv0_3WireFormat.decodeSignatureInfo(signatureHolder, decoder, copy);
decoder = new TlvDecoder(signatureValue);
signatureHolder.getSignature().setSignature
(new Blob(decoder.readBlobTlv(Tlv.SignatureValue), copy));
return signatureHolder.getSignature();
};
/**
* Encode the signatureValue in the Signature object as an NDN-TLV
* SignatureValue (the signature bits) and return the encoding.
* @param {Signature} signature An object of a subclass of Signature with the
* signature value to encode.
* @return {Blob} A Blob containing the encoding.
*/
Tlv0_3WireFormat.prototype.encodeSignatureValue = function(signature)
{
var encoder = new TlvEncoder(256);
encoder.writeBlobTlv(Tlv.SignatureValue, signature.getSignature().buf());
return new Blob(encoder.getOutput(), false);
};
/**
* Decode input as an NDN-TLV LpPacket and set the fields of the lpPacket object.
* @param {LpPacket} lpPacket The LpPacket object whose fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
*/
Tlv0_3WireFormat.prototype.decodeLpPacket = function(lpPacket, input, copy)
{
if (copy == null)
copy = true;
lpPacket.clear();
var decoder = new TlvDecoder(input);
var endOffset = decoder.readNestedTlvsStart(Tlv.LpPacket_LpPacket);
while (decoder.getOffset() < endOffset) {
// Imitate TlvDecoder.readTypeAndLength.
var fieldType = decoder.readVarNumber();
var fieldLength = decoder.readVarNumber();
var fieldEndOffset = decoder.getOffset() + fieldLength;
if (fieldEndOffset > input.length)
throw new DecodingException(new Error("TLV length exceeds the buffer length"));
if (fieldType == Tlv.LpPacket_Fragment) {
// Set the fragment to the bytes of the TLV value.
lpPacket.setFragmentWireEncoding
(new Blob(decoder.getSlice(decoder.getOffset(), fieldEndOffset), copy));
decoder.seek(fieldEndOffset);
// The fragment is supposed to be the last field.
break;
}
else if (fieldType == Tlv.LpPacket_Nack) {
var networkNack = new NetworkNack();
var code = decoder.readOptionalNonNegativeIntegerTlv
(Tlv.LpPacket_NackReason, fieldEndOffset);
var reason;
// The enum numeric values are the same as this wire format, so use as is.
if (code < 0 || code == NetworkNack.Reason.NONE)
// This includes an omitted NackReason.
networkNack.setReason(NetworkNack.Reason.NONE);
else if (code == NetworkNack.Reason.CONGESTION ||
code == NetworkNack.Reason.DUPLICATE ||
code == NetworkNack.Reason.NO_ROUTE)
networkNack.setReason(code);
else {
// Unrecognized reason.
networkNack.setReason(NetworkNack.Reason.OTHER_CODE);
networkNack.setOtherReasonCode(code);
}
lpPacket.addHeaderField(networkNack);
}
else if (fieldType == Tlv.LpPacket_IncomingFaceId) {
var incomingFaceId = new IncomingFaceId();
incomingFaceId.setFaceId(decoder.readNonNegativeInteger(fieldLength));
lpPacket.addHeaderField(incomingFaceId);
}
else if (fieldType == Tlv.LpPacket_CongestionMark) {
var congestionMark = new CongestionMark();
congestionMark.setCongestionMark(decoder.readNonNegativeInteger
(fieldLength));
lpPacket.addHeaderField(congestionMark);
}
else {
// Unrecognized field type. The conditions for ignoring are here:
// http://redmine.named-data.net/projects/nfd/wiki/NDNLPv2
var canIgnore =
(fieldType >= Tlv.LpPacket_IGNORE_MIN &&
fieldType <= Tlv.LpPacket_IGNORE_MAX &&
(fieldType & 0x03) == 0);
if (!canIgnore)
throw new DecodingException(new Error("Did not get the expected TLV type"));
// Ignore.
decoder.seek(fieldEndOffset);
}
decoder.finishNestedTlvs(fieldEndOffset);
}
decoder.finishNestedTlvs(endOffset);
};
/**
* Encode delegationSet as a sequence of NDN-TLV Delegation, and return the
* encoding. Note that the sequence of Delegation does not have an outer TLV
* type and length because it is intended to use the type and length of a Data
* packet's Content.
* @param {DelegationSet} delegationSet The DelegationSet object to encode.
* @return {Blob} A Blob containing the encoding.
*/
Tlv0_3WireFormat.prototype.encodeDelegationSet = function(delegationSet)
{
var encoder = new TlvEncoder(256);
Tlv0_3WireFormat.encodeDelegationSet_(delegationSet, encoder);
return new Blob(encoder.getOutput(), false);
};
/**
* Decode input as a sequence of NDN-TLV Delegation and set the fields of the
* delegationSet object. Note that the sequence of Delegation does not have an
* outer TLV type and length because it is intended to use the type and length
* of a Data packet's Content. This ignores any elements after the sequence
* of Delegation.
* @param {DelegationSet} delegationSet The DelegationSet object
* whose fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
*/
Tlv0_3WireFormat.prototype.decodeDelegationSet = function
(delegationSet, input, copy)
{
if (copy == null)
copy = true;
var decoder = new TlvDecoder(input);
Tlv0_3WireFormat.decodeDelegationSet_
(delegationSet, input.length, decoder, copy);
};
/**
* Encode the EncryptedContent v1 in NDN-TLV and return the encoding.
* @param {EncryptedContent} encryptedContent The EncryptedContent object to
* encode.
* @return {Blob} A Blob containing the encoding.
*/
Tlv0_3WireFormat.prototype.encodeEncryptedContent = function(encryptedContent)
{
var encoder = new TlvEncoder(256);
var saveLength = encoder.getLength();
// Encode backwards.
encoder.writeBlobTlv
(Tlv.Encrypt_EncryptedPayload, encryptedContent.getPayload().buf());
encoder.writeOptionalBlobTlv
(Tlv.Encrypt_InitialVector, encryptedContent.getInitialVector().buf());
// Assume the algorithmType value is the same as the TLV type.
encoder.writeNonNegativeIntegerTlv
(Tlv.Encrypt_EncryptionAlgorithm, encryptedContent.getAlgorithmType());
Tlv0_3WireFormat.encodeKeyLocator
(Tlv.KeyLocator, encryptedContent.getKeyLocator(), encoder);
encoder.writeTypeAndLength
(Tlv.Encrypt_EncryptedContent, encoder.getLength() - saveLength);
return new Blob(encoder.getOutput(), false);
};
/**
* Decode input as an EncryptedContent v1 in NDN-TLV and set the fields of the
* encryptedContent object.
* @param {EncryptedContent} encryptedContent The EncryptedContent object
* whose fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
*/
Tlv0_3WireFormat.prototype.decodeEncryptedContent = function
(encryptedContent, input, copy)
{
if (copy == null)
copy = true;
var decoder = new TlvDecoder(input);
var endOffset = decoder.
readNestedTlvsStart(Tlv.Encrypt_EncryptedContent);
encryptedContent.clear();
Tlv0_3WireFormat.decodeKeyLocator
(Tlv.KeyLocator, encryptedContent.getKeyLocator(), decoder, copy);
encryptedContent.setAlgorithmType
(decoder.readNonNegativeIntegerTlv(Tlv.Encrypt_EncryptionAlgorithm));
encryptedContent.setInitialVector
(new Blob(decoder.readOptionalBlobTlv
(Tlv.Encrypt_InitialVector, endOffset), copy));
encryptedContent.setPayload
(new Blob(decoder.readBlobTlv(Tlv.Encrypt_EncryptedPayload), copy));
decoder.finishNestedTlvs(endOffset);
};
/**
* Encode the EncryptedContent v2 (used in Name-based Access Control v2) in
* NDN-TLV and return the encoding.
* @param {EncryptedContent} encryptedContent The EncryptedContent object to
* encode.
* @return {Blob} A Blob containing the encoding.
*/
Tlv0_3WireFormat.prototype.encodeEncryptedContentV2 = function(encryptedContent)
{
var encoder = new TlvEncoder(256);
var saveLength = encoder.getLength();
// Encode backwards.
if (encryptedContent.getKeyLocator().getType() == KeyLocatorType.KEYNAME)
Tlv0_3WireFormat.encodeName
(encryptedContent.getKeyLocator().getKeyName(), encoder);
encoder.writeOptionalBlobTlv
(Tlv.Encrypt_EncryptedPayloadKey, encryptedContent.getPayloadKey().buf());
encoder.writeOptionalBlobTlv
(Tlv.Encrypt_InitialVector, encryptedContent.getInitialVector().buf());
encoder.writeBlobTlv
(Tlv.Encrypt_EncryptedPayload, encryptedContent.getPayload().buf());
encoder.writeTypeAndLength
(Tlv.Encrypt_EncryptedContent, encoder.getLength() - saveLength);
return new Blob(encoder.getOutput(), false);
};
/**
* Decode input as an EncryptedContent v2 (used in Name-based Access Control
* v2) in NDN-TLV and set the fields of the encryptedContent object.
* See https://github.com/named-data/name-based-access-control/blob/new/docs/spec.rst .
* @param {EncryptedContent} encryptedContent The EncryptedContent object
* whose fields are updated.
* @param {Buffer} input The buffer with the bytes to decode.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
*/
Tlv0_3WireFormat.prototype.decodeEncryptedContentV2 = function
(encryptedContent, input, copy)
{
if (copy == null)
copy = true;
var decoder = new TlvDecoder(input);
var endOffset = decoder.
readNestedTlvsStart(Tlv.Encrypt_EncryptedContent);
encryptedContent.clear();
encryptedContent.setPayload
(new Blob(decoder.readBlobTlv(Tlv.Encrypt_EncryptedPayload), copy));
encryptedContent.setInitialVector
(new Blob(decoder.readOptionalBlobTlv
(Tlv.Encrypt_InitialVector, endOffset), copy));
encryptedContent.setPayloadKey
(new Blob(decoder.readOptionalBlobTlv
(Tlv.Encrypt_EncryptedPayloadKey, endOffset), copy));
if (decoder.peekType(Tlv.Name, endOffset)) {
Tlv0_3WireFormat.decodeName
(encryptedContent.getKeyLocator().getKeyName(), decoder, copy);
encryptedContent.getKeyLocator().setType(KeyLocatorType.KEYNAME);
}
decoder.finishNestedTlvs(endOffset);
};
/**
* Get a singleton instance of a Tlv0_3WireFormat. To always use the
* preferred version NDN-TLV, you should use TlvWireFormat.get().
* @return {Tlv0_3WireFormat} The singleton instance.
*/
Tlv0_3WireFormat.get = function()
{
if (Tlv0_3WireFormat.instance === null)
Tlv0_3WireFormat.instance = new Tlv0_3WireFormat();
return Tlv0_3WireFormat.instance;
};
/**
* Encode the name component to the encoder as NDN-TLV. This handles different
* component types such as ImplicitSha256DigestComponent.
* @param {Name.Component} component The name component to encode.
* @param {TlvEncoder} encoder The encoder to receive the encoding.
*/
Tlv0_3WireFormat.encodeNameComponent = function(component, encoder)
{
var type;
if (component.getType() === ComponentType.OTHER_CODE)
type = component.getOtherTypeCode();
else
// The enum values are the same as the TLV type codes.
type = component.getType();
encoder.writeBlobTlv(type, component.getValue().buf());
};
/**
* Decode the name component as NDN-TLV and return the component. This handles
* different component types such as ImplicitSha256DigestComponent.
* @param {TlvDecoder} decoder The decoder with the input.
* @param {boolean} copy (optional) If true, copy from the input when making new
* Blob values. If false, then Blob values share memory with the input, which
* must remain unchanged while the Blob values are used. If omitted, use true.
* @return {Name.Component} A new Name.Component.
*/
Tlv0_3WireFormat.decodeNameComponent = function(decoder, copy)
{
if (copy == null)
copy = true;
var savePosition = decoder.getOffset();
var type = decoder.readVarNumber();
// Restore the position.
decoder.seek(savePosition);
var value = new Blob(decoder.readBlobTlv(type), copy);
if (type === Tlv.ImplicitSha256DigestComponent)
return Name.Component.fromImplicitSha256Digest(value);
else if (type === Tlv.ParametersSha256DigestComponent)
return Name.Component.fromParametersSha256Digest(value);
else if (type === Tlv.NameComponent)
return new Name.Component(value);
else
// Unrecognized type code.
return new Name.Component(value, ComponentType.OTHER_CODE, type);
};
/**
* Encode the name to the encoder.
* @param {Name} name The name to encode.
* @param {TlvEncoder} encoder The encoder to receive the encoding.
* @return {object} An associative array with fields
* (signedPortionBeginOffset, signedPortionEndOffset) where
* signedPortionBeginOffset is the offset in the encoding of the beginning of
* the signed portion, and signedPortionEndOffset is the offset in the encoding
* of the end of the signed portion. The signed portion starts from the first
* name component and ends just before the final name component (which is
* assumed to be a signature for a signed interest).
*/
Tlv0_3WireFormat.encodeName = function(name, encoder)
{
var saveLength = encoder.getLength();
// Encode the components backwards.
var signedPortionEndOffsetFromBack;
for (var i = name.size() - 1; i >= 0; --i) {
Tlv0_3WireFormat.encodeNameComponent(name.get(i), encoder);
if (i == name.size() - 1)
signedPortionEndOffsetFromBack = encoder.getLength();
}
var signedPortionBeginOffsetFromBack = encoder.getLength();
encoder.writeTypeAndLength(Tlv.Name, encoder.getLength() - saveLength);
var signedPortionBeginOffset =
encoder.getLength() - signedPortionBeginOffsetFromBack;
var signedPortionEndOffset;
if (name.size() == 0)
// There is no "final component", so set signedPortionEndOffset arbitrarily.
signedPortionEndOffset = signedPortionBeginOffset;
else
signedPortionEndOffset = encoder.getLength() - signedPortionEndOffsetFromBack;
return { signedPortionBeginOffset: signedPortionBeginOffset,
signedPortionEndOffset: signedPortionEndOffset };
};
/**
* Clear the name, decode a Name from the decoder and set the fields of the name
* object.
* @param {Name} name The name object whose fields are updated.
* @param {TlvDecoder} decoder The decoder with the input.
* @return {object} An associative array with fields
* (signedPortionBeginOffset, signedPortionEndOffset) where
* signedPortionBeginOffset is the offset in the encoding of the beginning of
* the signed portion, and signedPortionEndOffset is the offset in the encoding
* of the end of the signed portion. The signed portion starts from the first
* name component and ends just before the final name component (which is
* assumed to be a signature for a signed interest).
*/
Tlv0_3WireFormat.decodeName = function(name, decoder, copy)
{
name.clear();
var endOffset = decoder.readNestedTlvsStart(Tlv.Name);
var signedPortionBeginOffset = decoder.getOffset();
// In case there are no components, set signedPortionEndOffset arbitrarily.
var signedPortionEndOffset = signedPortionBeginOffset;
while (decoder.getOffset() < endOffset) {
signedPortionEndOffset = decoder.getOffset();
name.append(Tlv0_3WireFormat.decodeNameComponent(decoder, copy));
}
decoder.finishNestedTlvs(endOffset);
return { signedPortionBeginOffset: signedPortionBeginOffset,
signedPortionEndOffset: signedPortionEndOffset };
};
/**
* Encode the interest selectors. If no selectors are written, do not output a
* Selectors TLV.
*/
Tlv0_3WireFormat.encodeSelectors = function(interest, encoder)
{
var saveLength = encoder.getLength();
// Encode backwards.
if (interest.getMustBeFresh())
encoder.writeTypeAndLength(Tlv.MustBeFresh, 0);
encoder.writeOptionalNonNegativeIntegerTlv(
Tlv.ChildSelector, interest.getChildSelector());
if (interest.getExclude().size() > 0)
Tlv0_3WireFormat.encodeExclude(interest.getExclude(), encoder);
if (interest.getKeyLocator().getType() != null)
Tlv0_3WireFormat.encodeKeyLocator
(Tlv.PublisherPublicKeyLocator, interest.getKeyLocator(), encoder);
encoder.writeOptionalNonNegativeIntegerTlv(
Tlv.MaxSuffixComponents, interest.getMaxSuffixComponents());
encoder.writeOptionalNonNegativeIntegerTlv(
Tlv.MinSuffixComponents, interest.getMinSuffixComponents());
// Only output the type and length if values were written.
if (encoder.getLength() != saveLength)
encoder.writeTypeAndLength(Tlv.Selectors, encoder.getLength() - saveLength);
};
Tlv0_3WireFormat.decodeSelectors = function(interest, decoder, copy)
{
if (copy == null)
copy = true;
var endOffset = decoder.readNestedTlvsStart(Tlv.Selectors);
interest.setMinSuffixComponents(decoder.readOptionalNonNegativeIntegerTlv
(Tlv.MinSuffixComponents, endOffset));
interest.setMaxSuffixComponents(decoder.readOptionalNonNegativeIntegerTlv
(Tlv.MaxSuffixComponents, endOffset));
if (decoder.peekType(Tlv.PublisherPublicKeyLocator, endOffset))
Tlv0_3WireFormat.decodeKeyLocator
(Tlv.PublisherPublicKeyLocator, interest.getKeyLocator(), decoder, copy);
else
interest.getKeyLocator().clear();
if (decoder.peekType(Tlv.Exclude, endOffset))
Tlv0_3WireFormat.decodeExclude(interest.getExclude(), decoder, copy);
else
interest.getExclude().clear();
interest.setChildSelector(decoder.readOptionalNonNegativeIntegerTlv
(Tlv.ChildSelector, endOffset));
interest.setMustBeFresh(decoder.readBooleanTlv(Tlv.MustBeFresh, endOffset));
decoder.finishNestedTlvs(endOffset);
};
Tlv0_3WireFormat.encodeExclude = function(exclude, encoder)
{
var saveLength = encoder.getLength();
// TODO: Do we want to order the components (except for ANY)?
// Encode the entries backwards.
for (var i = exclude.size() - 1; i >= 0; --i) {
var entry = exclude.get(i);
if (entry == Exclude.ANY)
encoder.writeTypeAndLength(Tlv.Any, 0);
else
Tlv0_3WireFormat.encodeNameComponent(entry, encoder);
}
encoder.writeTypeAndLength(Tlv.Exclude, encoder.getLength() - saveLength);
};
Tlv0_3WireFormat.decodeExclude = function(exclude, decoder, copy)
{
if (copy == null)
copy = true;
var endOffset = decoder.readNestedTlvsStart(Tlv.Exclude);
exclude.clear();
while (decoder.getOffset() < endOffset) {
if (decoder.peekType(Tlv.Any, endOffset)) {
// Read past the Any TLV.
decoder.readBooleanTlv(Tlv.Any, endOffset);
exclude.appendAny();
}
else
exclude.appendComponent(Tlv0_3WireFormat.decodeNameComponent(decoder, copy));
}
decoder.finishNestedTlvs(endOffset);
};
Tlv0_3WireFormat.encodeKeyLocator = function(type, keyLocator, encoder)
{
var saveLength = encoder.getLength();
// Encode backwards.
if (keyLocator.getType() != null) {
if (keyLocator.getType() == KeyLocatorType.KEYNAME)
Tlv0_3WireFormat.encodeName(keyLocator.getKeyName(), encoder);
else if (keyLocator.getType() == KeyLocatorType.KEY_LOCATOR_DIGEST &&
keyLocator.getKeyData().size() > 0)
encoder.writeBlobTlv(Tlv.KeyLocatorDigest, keyLocator.getKeyData().buf());
else
throw new Error("Unrecognized KeyLocatorType " + keyLocator.getType());
}
encoder.writeTypeAndLength(type, encoder.getLength() - saveLength);
};
Tlv0_3WireFormat.decodeKeyLocator = function
(expectedType, keyLocator, decoder, copy)
{
if (copy == null)
copy = true;
var endOffset = decoder.readNestedTlvsStart(expectedType);
keyLocator.clear();
if (decoder.getOffset() == endOffset)
// The KeyLocator is omitted, so leave the fields as none.
return;
if (decoder.peekType(Tlv.Name, endOffset)) {
// KeyLocator is a Name.
keyLocator.setType(KeyLocatorType.KEYNAME);
Tlv0_3WireFormat.decodeName(keyLocator.getKeyName(), decoder, copy);
}
else if (decoder.peekType(Tlv.KeyLocatorDigest, endOffset)) {
// KeyLocator is a KeyLocatorDigest.
keyLocator.setType(KeyLocatorType.KEY_LOCATOR_DIGEST);
keyLocator.setKeyData
(new Blob(decoder.readBlobTlv(Tlv.KeyLocatorDigest), copy));
}
else
throw new DecodingException(new Error
("decodeKeyLocator: Unrecognized key locator type"));
decoder.finishNestedTlvs(endOffset);
};
Tlv0_3WireFormat.encodeValidityPeriod_ = function(validityPeriod, encoder)
{
var saveLength = encoder.getLength();
// Encode backwards.
encoder.writeBlobTlv(Tlv.ValidityPeriod_NotAfter,
new Blob(Schedule.toIsoString(validityPeriod.getNotAfter())).buf());
encoder.writeBlobTlv(Tlv.ValidityPeriod_NotBefore,
new Blob(Schedule.toIsoString(validityPeriod.getNotBefore())).buf());
encoder.writeTypeAndLength
(Tlv.ValidityPeriod_ValidityPeriod, encoder.getLength() - saveLength);
};
Tlv0_3WireFormat.decodeValidityPeriod_ = function(validityPeriod, decoder)
{
var endOffset = decoder.readNestedTlvsStart(Tlv.ValidityPeriod_ValidityPeriod);
validityPeriod.clear();
// Set copy false since we just immediately get the string.
var isoString = new Blob
(decoder.readBlobTlv(Tlv.ValidityPeriod_NotBefore), false);
var notBefore = Schedule.fromIsoString(isoString.toString());
isoString = new Blob
(decoder.readBlobTlv(Tlv.ValidityPeriod_NotAfter), false);
var notAfter = Schedule.fromIsoString(isoString.toString());
validityPeriod.setPeriod(notBefore, notAfter);
decoder.finishNestedTlvs(endOffset);
};
/**
* An internal method to encode signature as the appropriate form of
* SignatureInfo in NDN-TLV.
* @param {Signature} signature An object of a subclass of Signature to encode.
* @param {TlvEncoder} encoder The encoder.
*/
Tlv0_3WireFormat.encodeSignatureInfo_ = function(signature, encoder)
{
if (signature instanceof GenericSignature) {
// Handle GenericSignature separately since it has the entire encoding.
var encoding = signature.getSignatureInfoEncoding();
// Do a test decoding to sanity check that it is valid TLV.
try {
var decoder = new TlvDecoder(encoding.buf());
var endOffset = decoder.readNestedTlvsStart(Tlv.SignatureInfo);
decoder.readNonNegativeIntegerTlv(Tlv.SignatureType);
// Skip unrecognized TLVs, even if they have a critical type code.
decoder.finishNestedTlvs(endOffset, true);
} catch (ex) {
throw new Error
("The GenericSignature encoding is not a valid NDN-TLV SignatureInfo: " +
ex.message);
}
encoder.writeBuffer(encoding.buf());
return;
}
var saveLength = encoder.getLength();
// Encode backwards.
if (signature instanceof Sha256WithRsaSignature) {
if (signature.getValidityPeriod().hasPeriod())
Tlv0_3WireFormat.encodeValidityPeriod_
(signature.getValidityPeriod(), encoder);
Tlv0_3WireFormat.encodeKeyLocator
(Tlv.KeyLocator, signature.getKeyLocator(), encoder);
encoder.writeNonNegativeIntegerTlv
(Tlv.SignatureType, Tlv.SignatureType_SignatureSha256WithRsa);
}
else if (signature instanceof Sha256WithEcdsaSignature) {
if (signature.getValidityPeriod().hasPeriod())
Tlv0_3WireFormat.encodeValidityPeriod_
(signature.getValidityPeriod(), encoder);
Tlv0_3WireFormat.encodeKeyLocator
(Tlv.KeyLocator, signature.getKeyLocator(), encoder);
encoder.writeNonNegativeIntegerTlv
(Tlv.SignatureType, Tlv.SignatureType_SignatureSha256WithEcdsa);
}
else if (signature instanceof HmacWithSha256Signature) {
Tlv0_3WireFormat.encodeKeyLocator
(Tlv.KeyLocator, signature.getKeyLocator(), encoder);
encoder.writeNonNegativeIntegerTlv
(Tlv.SignatureType, Tlv.SignatureType_SignatureHmacWithSha256);
}
else if (signature instanceof DigestSha256Signature)
encoder.writeNonNegativeIntegerTlv
(Tlv.SignatureType, Tlv.SignatureType_DigestSha256);
else
throw new Error("encodeSignatureInfo: Unrecognized Signature object type");
encoder.writeTypeAndLength(Tlv.SignatureInfo, encoder.getLength() - saveLength);
};
Tlv0_3WireFormat.decodeSignatureInfo = function(data, decoder, copy)
{
if (copy == null)
copy = true;
var beginOffset = decoder.getOffset();
var endOffset = decoder.readNestedTlvsStart(Tlv.SignatureInfo);
var signatureType = decoder.readNonNegativeIntegerTlv(Tlv.SignatureType);
if (signatureType == Tlv.SignatureType_SignatureSha256WithRsa) {
data.setSignature(new Sha256WithRsaSignature());
// Modify data's signature object because if we create an object
// and set it, then data will have to copy all the fields.
var signatureInfo = data.getSignature();
Tlv0_3WireFormat.decodeKeyLocator
(Tlv.KeyLocator, signatureInfo.getKeyLocator(), decoder, copy);
if (decoder.peekType(Tlv.ValidityPeriod_ValidityPeriod, endOffset))
Tlv0_3WireFormat.decodeValidityPeriod_
(signatureInfo.getValidityPeriod(), decoder);
}
else if (signatureType == Tlv.SignatureType_SignatureSha256WithEcdsa) {
data.setSignature(new Sha256WithEcdsaSignature());
var signatureInfo = data.getSignature();
Tlv0_3WireFormat.decodeKeyLocator
(Tlv.KeyLocator, signatureInfo.getKeyLocator(), decoder, copy);
if (decoder.peekType(Tlv.ValidityPeriod_ValidityPeriod, endOffset))
Tlv0_3WireFormat.decodeValidityPeriod_
(signatureInfo.getValidityPeriod(), decoder);
}
else if (signatureType == Tlv.SignatureType_SignatureHmacWithSha256) {
data.setSignature(new HmacWithSha256Signature());
var signatureInfo = data.getSignature();
Tlv0_3WireFormat.decodeKeyLocator
(Tlv.KeyLocator, signatureInfo.getKeyLocator(), decoder, copy);
}
else if (signatureType == Tlv.SignatureType_DigestSha256)
data.setSignature(new DigestSha256Signature());
else {
data.setSignature(new GenericSignature());
var signatureInfo = data.getSignature();
// Get the bytes of the SignatureInfo TLV.
signatureInfo.setSignatureInfoEncoding
(new Blob(decoder.getSlice(beginOffset, endOffset), copy), signatureType);
// Skip the remaining TLVs now, allowing unrecognized critical type codes.
decoder.finishNestedTlvs(endOffset, true);
}
decoder.finishNestedTlvs(endOffset);
};
Tlv0_3WireFormat.encodeMetaInfo = function(metaInfo, encoder)
{
var saveLength = encoder.getLength();
// Encode backwards.
var finalBlockIdBuf = metaInfo.getFinalBlockId().getValue().buf();
if (finalBlockIdBuf != null && finalBlockIdBuf.length > 0) {
// FinalBlockId has an inner NameComponent.
var finalBlockIdSaveLength = encoder.getLength();
Tlv0_3WireFormat.encodeNameComponent(metaInfo.getFinalBlockId(), encoder);
encoder.writeTypeAndLength
(Tlv.FinalBlockId, encoder.getLength() - finalBlockIdSaveLength);
}
encoder.writeOptionalNonNegativeIntegerTlv
(Tlv.FreshnessPeriod, metaInfo.getFreshnessPeriod());
if (metaInfo.getType() != ContentType.BLOB) {
// Not the default, so we need to encode the type.
if (metaInfo.getType() == ContentType.LINK ||
metaInfo.getType() == ContentType.KEY ||
metaInfo.getType() == ContentType.NACK)
// The ContentType enum is set up with the correct integer for
// each NDN-TLV ContentType.
encoder.writeNonNegativeIntegerTlv(Tlv.ContentType, metaInfo.getType());
else if (metaInfo.getType() == ContentType.OTHER_CODE)
encoder.writeNonNegativeIntegerTlv
(Tlv.ContentType, metaInfo.getOtherTypeCode());
else
// We don't expect this to happen.
throw new Error("unrecognized TLV ContentType");
}
encoder.writeTypeAndLength(Tlv.MetaInfo, encoder.getLength() - saveLength);
};
Tlv0_3WireFormat.decodeMetaInfo = function(metaInfo, decoder, copy)
{
if (copy == null)
copy = true;
var endOffset = decoder.readNestedTlvsStart(Tlv.MetaInfo);
var type = decoder.readOptionalNonNegativeIntegerTlv
(Tlv.ContentType, endOffset);
if (type == null || type < 0 || type === ContentType.BLOB)
metaInfo.setType(ContentType.BLOB);
else if (type === ContentType.LINK ||
type === ContentType.KEY ||
type === ContentType.NACK)
// The ContentType enum is set up with the correct integer for each NDN-TLV
// ContentType.
metaInfo.setType(type);
else {
// Unrecognized content type.
metaInfo.setType(ContentType.OTHER_CODE);
metaInfo.setOtherTypeCode(type);
}
metaInfo.setFreshnessPeriod
(decoder.readOptionalNonNegativeIntegerTlv(Tlv.FreshnessPeriod, endOffset));
if (decoder.peekType(Tlv.FinalBlockId, endOffset)) {
var finalBlockIdEndOffset = decoder.readNestedTlvsStart(Tlv.FinalBlockId);
metaInfo.setFinalBlockId(Tlv0_3WireFormat.decodeNameComponent(decoder, copy));
decoder.finishNestedTlvs(finalBlockIdEndOffset);
}
else
metaInfo.setFinalBlockId(null);
decoder.finishNestedTlvs(endOffset);
};
Tlv0_3WireFormat.encodeControlParameters = function(controlParameters, encoder)
{
var saveLength = encoder.getLength();
// Encode backwards.
encoder.writeOptionalNonNegativeIntegerTlv
(Tlv.ControlParameters_ExpirationPeriod,
controlParameters.getExpirationPeriod());
if (controlParameters.getStrategy().size() > 0){
var strategySaveLength = encoder.getLength();
Tlv0_3WireFormat.encodeName(controlParameters.getStrategy(), encoder);
encoder.writeTypeAndLength(Tlv.ControlParameters_Strategy,
encoder.getLength() - strategySaveLength);
}
var flags = controlParameters.getForwardingFlags().getNfdForwardingFlags();
if (flags != new RegistrationOptions().getNfdForwardingFlags())
// The flags are not the default value.
encoder.writeNonNegativeIntegerTlv
(Tlv.ControlParameters_Flags, flags);
encoder.writeOptionalNonNegativeIntegerTlv
(Tlv.ControlParameters_Cost, controlParameters.getCost());
encoder.writeOptionalNonNegativeIntegerTlv
(Tlv.ControlParameters_Origin, controlParameters.getOrigin());
encoder.writeOptionalNonNegativeIntegerTlv
(Tlv.ControlParameters_LocalControlFeature,
controlParameters.getLocalControlFeature());
if (controlParameters.getUri().length != 0)
encoder.writeBlobTlv
(Tlv.ControlParameters_Uri, new Blob(controlParameters.getUri()).buf());
encoder.writeOptionalNonNegativeIntegerTlv
(Tlv.ControlParameters_FaceId, controlParameters.getFaceId());
if (controlParameters.getName() != null)
Tlv0_3WireFormat.encodeName(controlParameters.getName(), encoder);
encoder.writeTypeAndLength
(Tlv.ControlParameters_ControlParameters, encoder.getLength() - saveLength);
};
Tlv0_3WireFormat.decodeControlParameters = function
(controlParameters, decoder, copy)
{
if (copy == null)
copy = true;
controlParameters.clear();
var endOffset = decoder.
readNestedTlvsStart(Tlv.ControlParameters_ControlParameters);
// decode name
if (decoder.peekType(Tlv.Name, endOffset)) {
var name = new Name();
Tlv0_3WireFormat.decodeName(name, decoder, copy);
controlParameters.setName(name);
}
// decode face ID
controlParameters.setFaceId(decoder.readOptionalNonNegativeIntegerTlv
(Tlv.ControlParameters_FaceId, endOffset));
// decode URI
if (decoder.peekType(Tlv.ControlParameters_Uri, endOffset)) {
// Set copy false since we just immediately get the string.
var uri = new Blob
(decoder.readOptionalBlobTlv(Tlv.ControlParameters_Uri, endOffset), false);
controlParameters.setUri(uri.toString());
}
decoder.skipOptionalTlv(Tlv.ControlParameters_LocalUri, endOffset);
// decode integers
controlParameters.setLocalControlFeature(decoder.
readOptionalNonNegativeIntegerTlv(
Tlv.ControlP